安卓动画在onAnimationEnd方法中未完成。

70
似乎在触发onAnimationEnd事件时,安卓动画并没有真正完成,尽管animation.hasEnded已经设置为true。
我想让我的视图在其ScaleAnimation结束时更改其背景drawable,它确实会更改,但可以清楚地看到它在完成前几毫秒就被更改了。问题是,新的背景出现(=正在)被缩放一小段时间,直到动画真正完成,这导致它闪烁。
有没有办法获得动画的真正结束或者只是防止新的背景在这个短时间内被缩放?
谢谢!
//编辑: 我使用 AnimationListener 来获取以下调用:
    @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
}

1
你是否使用AnimationListener来获取OnAnimationEnd调用,或者其他方式?你能否发布你项目中相关的代码,这样我们就可以更好地了解正在发生的事情? - FoamyGuy
当然,谢谢! 我正在编辑问题以添加代码和一些细节。 - ShadowMare
请问ShadowMare能帮我一下吗?我遇到了同样的问题,不知道该如何解决。 - Milos Cuculovic
你尝试使用下面提供的代码了吗?这个方法对我很有效。基本上让视图处理onAnimationEnd,而不是让动画本身处理。如果需要更多帮助,请告诉我。 - ShadowMare
嗨@ShadowMare,你能帮我解决这个问题吗?因为我遇到了类似的问题。 - Milos Cuculovic
你尝试过将OnAnimationEnd添加到ImageView而不是动画本身吗?你必须在那里处理动画的结束,它应该可以工作。我需要更多的代码以获得进一步的帮助。 - ShadowMare
12个回答

94

这里实际上与此问题相关的错误是http://code.google.com/p/android-misc-widgets/issues/detail?id=8

这基本上表明,当AnimationListener附加到动画时,onAnimationEnd方法不起作用。

解决方法是在应用动画的视图中监听动画事件。例如,如果最初您像这样将动画监听器附加到动画:

mAnimation.setAnimationListener(new AnimationListener() {
    @Override
    public void onAnimationEnd(Animation arg0) {
        //Functionality here
    }
});
并将该动画应用于 ImageView,例如:
mImageView.startAnimation(mAnimation);
为了解决这个问题,现在您必须创建一个自定义的ImageView。
public class MyImageView extends ImageView {

然后覆盖View类的onAnimationEnd方法,在那里提供所有功能。

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

这是解决此问题的正确方法,将功能提供在重写的View的onAnimationEnd方法中,而不是附加到动画的AnimationListener的onAnimationEnd方法中。

这样做可以正常工作,动画末尾不再出现闪烁问题。


请问能帮我一下吗,Soham?我和您碰到同样的问题,但是不知道该怎么解决。 - Milos Cuculovic
2
是的,我确实将动画应用于imageView。我已经创建了视图类,但我从未进入onAnimationEnd函数。 - Milos Cuculovic
2
那么使用内容视图布局呢?在这种情况下,您不能使用嵌套类和因此父类功能。 - Konstantin Konopko
@Soham 如果 View 对象需要执行一些动画,该怎么办? - TOP
3
我们无法再通过该链接查看错误,但在Android M、N等版本中仍然存在此问题。 - androidguy
显示剩余4条评论

32
我通过在 onAnimationEnd 中调用正在被动画化的视图上的 clearAnimation() 方法来解决了这个问题,这样就消除了闪烁。
很奇怪为什么任何人都必须这样做,因为只有当动画已经结束时才应该调用 onAnimationEnd 回调。但我想答案在于框架如何处理视图/布局动画回调的深度。
暂时把它看作是一个无需 hack 的解决方案,它只是有效地工作。
        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);

1
那对我的情况没有帮助。不过,Soham的建议确实有用。 - Kris Van Bael
1
哇!简单的一行解决方案,像魔法一样奏效!我只是在我的“view.layout()”之前添加了“view.clearAnimation();”,然后就完成了! :-) - Brad
1
我差点就爱上你了兄弟!看了5个小时的代码,想自杀;)你救了我的命! - sennin
6
调用clearAnimation()会触发另一个onAnimationEnd的调用! - Leeeeeeelo
挽救了我的生命!干杯 - Thijs Limmen

7

我曾经遇到过同样的问题,通过以下方法解决了它:

view.clearAnimation();

之前

view.startAnimation(anim);

在设置动画后调用view.invalidate(),这对我很有效,并且动画监听器重新开始工作。 - Pushpan

6

我曾遇到类似的问题,我使用了Soham提供的自定义视图类解决了这个问题。

它运行良好,但最后,我发现了一个更简单的解决方案,适用于我。

在调用view.StartAnimation(animation)之后,在我的程序下一步之前,我添加了一个短暂的延迟时间,足以让动画完成,但对用户来说又不会太明显:

new Handler().postDelayed(new Runnable() {
       @Override
       public void run() {
           nextStepInMyProgram();
       }
     }, 200);// delay in milliseconds (200)

2
一个可行但不太好的解决方案,它可以在不覆盖类的情况下工作,并且仅使用post(Runnable),而不是postDelayed(Runnable, int)。 - Massimo
Massimo - post(Runnable) 不让动画完成,所以 Doigen 是正确的,必须使用 postDelayed(Runnable)。只需要做一个小修正,我们可以使用 delay = "animation.getDuration()"。 - Ankit Bansal
这可以与AnimatorSet一起使用,在onAnimationStart中设置函数即可实现。 - ElYeante
这个解决方案不仅糟糕,而且不完整:它不能覆盖所有情况。如果在 nextStepInMyProgram() 之后有更多的动画触发,你将会遇到副作用。 - boctulus

2

尝试使用您的对象中的getAnimation()方法:

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
            }
        });
}

2

由于某些原因,onAnimationStart正常工作,而onAnimationEnd则不正常。以下是我最初的做法以及所做出的更改:

尝试1(闪烁): a)将图像从0px移动到80px b)在onAnimationEnd中,将图像位置设置为80px

尝试2(无闪烁): a)在onAnimationStart中,将图像位置设置为80px b)将图像从-80px移动到0px

希望这讲得清楚。基本上我调整了做法。


通过使用翻译动画,这样会更好。 - Daniel Benedykt

1

一个简单的解决方法是在AnimationListener.onAnimationEnd()中添加一行代码:

@Override 
public void onAnimationEnd(Animation a) {
    a.setAnimationListener(null);
    …
}

1

动画也可以在屏幕旋转时停止。在这种情况下,onAnimationEnd()不会被调用。我的解决方法:

 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);

0
我遇到了这个问题,因为我的Animation没有在主线程中启动。 这导致了一个持续时间为0的duration。 然而,Animation确实正确播放 - 它只是在执行后立即调用了onAnimationEnd()

0
如果您将重复次数设置为无限,则onAnimationEnd不会被调用。请查看文档link

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接