Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android animation is not finished in onAnimationEnd

It seems that an android animation is not truly finished when the onAnimationEnd event is fired although animation.hasEnded is set to true.

I want my view to change it's background drawable on the end of it's ScaleAnimation which it does, but you can clearly see that it is changed some miliseconds before it finishes. The problem is, that it flickers because the new background appears (=is) scaled for a short time until the animation really finishes.

Is there a way to get either the real end of the animation or just prevent the new background from beeing scaled this short period of time?

Thank you!


//EDIT: I'm using an AnimationListener to get the following call:

    @Override
public void onAnimationEnd(Animation animation)
{
    View view = (MyView) ((ExtendedScaleAnimation) animation).getView();

    view.clearAnimation();
    view.requestLayout();
    view.refreshBackground(); // <-- this is where the background gets changed
}
like image 260
ShadowMare Avatar asked Jan 20 '11 18:01

ShadowMare


People also ask

How do I turn off infinite animation on Android?

Use clearAnimation() to stop an animation.

Is animation possible on Android?

On Android 4.4 (API level 19) and higher, you can use the transition framework to create animations when you swap the layout within the current activity or fragment. All you need to do is specify the starting and ending layout, and what type of animation you want to use.


8 Answers

Here is the actual bug related to this issue http://code.google.com/p/android-misc-widgets/issues/detail?id=8

This basically states that the onAnimationEnd method doesn't really work well when an AnimationListener is attached to an Animation

The workaround is to listen for the animation events in the view to which you were applying the animation to For example if initially you were attaching the animation listener to the animation like this

mAnimation.setAnimationListener(new AnimationListener() {
    @Override
    public void onAnimationEnd(Animation arg0) {
        //Functionality here
    }
});

and then applying to the animation to a ImageView like this

mImageView.startAnimation(mAnimation);

To work around this issue, you must now create a custom ImageView

public class MyImageView extends ImageView {

and then override the onAnimationEnd method of the View class and provide all the functionality there

@Override
protected void onAnimationEnd() {
    super.onAnimationEnd();
    //Functionality here
}

This is the proper workaround for this issue, provide the functionality in the over-riden View -> onAnimationEnd method as opposed to the onAnimationEnd method of the AnimationListener attached to the Animation.

This works properly and there is no longer any flicker towards the end of the animation. Hope this helps.

like image 83
Soham Avatar answered Oct 08 '22 09:10

Soham


I was abe to resolve this by calling clearAnimation() on the view being animated inside onAnimationEnd, that took away the flicker Its weird why would anyone have to do that, as onAnimationEnd callback should have been called only if the animation has already ended. But I guess the answer lies in the depth of Framework on how view/layout handles animation callback. For now take it as a hack-free solution, that just works.

        animation.setAnimationListener(new AnimationListener() {

        public void onAnimationEnd(Animation anim) {
            innerView.clearAnimation();   // to get rid of flicker at end of animation

            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams
            (innerBlockContainer.getWidth(), innerBlockContainer.getHeight());

            /* Update lp margin, left/top to update layout after end of Translation */
            ViewGroup parent_ofInnerView = (ViewGroup)innerView.getParent();
            vp.updateViewLayout(innerBlockContainer, lp);

        }

        public void onAnimationRepeat(Animation arg0) {}

        public void onAnimationStart(Animation arg0) {
        }

    });

     innerView.startAnimation(animation);
like image 27
lucknow_rocks Avatar answered Oct 08 '22 11:10

lucknow_rocks


I had a similar problem and I used Soham's solution with custom view class.

It worked fine, but at the end, I've found a simpler solution that worked for me.

After calling the view.StartAnimation(animation), and before the next step in my program, I've added a short delay that will be long enough to let the animation finish, but short enough to be unnoticeable by the user:

new Handler().postDelayed(new Runnable() {
       @Override
       public void run() {
           nextStepInMyProgram();
       }
     }, 200);// delay in milliseconds (200)
like image 42
Doigen Avatar answered Oct 08 '22 11:10

Doigen


I had same issue and solved it using

view.clearAnimation();

before

view.startAnimation(anim);
like image 34
savepopulation Avatar answered Oct 08 '22 11:10

savepopulation


For some reason the onAnimationStart works properly, and the onAnimationEnd doesnt. So heres how I originally did it and what I changed:

Attempt 1 (flicker): a) Move image from 0px to 80px b) In onAnimationEnd, set the image's location to 80px

Attempt 2 (no flicker): a) In onAnimationStart, set the image's location to 80px b) Move the image from -80px to 0px

Hope that made sense. Basically I flipped the way I did it

like image 25
Matt Avatar answered Oct 08 '22 11:10

Matt


Try to use getAnimation() from your object:

public void onShowListBtnClick(View view)
    {
        rightPanel.startAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_left));

        rightPanel.getAnimation().setAnimationListener(new Animation.AnimationListener() {    
            @Override
            public void onAnimationStart(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                // write your code here
            }
        });
}
like image 40
Butsaty Avatar answered Oct 08 '22 10:10

Butsaty


An easy fix is to add one line to AnimationListener.onAnimationEnd():

@Override 
public void onAnimationEnd(Animation a) {
    a.setAnimationListener(null);
    …
}
like image 45
Alex Cohn Avatar answered Oct 08 '22 10:10

Alex Cohn


annimation can be also stopped on screen rotation. in this case onAnimationEnd() is not being called. my workaround:

 animation.setDuration(animationDuration);
 animation.setAnimationListener(new AnimationListenerAdapter() {...});
 view.startAnimation(animation);
 handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if(!animation.hasEnded()) {
                    // here you can handle this case
                }
            }
        }, animationDuration + 100);
like image 25
Oleg Khalidov Avatar answered Oct 08 '22 10:10

Oleg Khalidov