Android动画不重复


85

我正在尝试制作简单的动画,该动画将重复几次(或无限次)。
看来android:repeatCount不行!
这是我的动画资源,来自/res/anim/first_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false"
    android:repeatCount="infinite"
    >
    <scale
        android:interpolator="@android:anim/decelerate_interpolator"
        android:duration="500"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:toXScale="1.2"
        android:toYScale="1.2"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="false" />
    <scale
        android:interpolator="@android:anim/accelerate_interpolator"
        android:startOffset="500"
        android:duration="500"
        android:fromXScale="1.2"
        android:fromYScale="1.2"
        android:toXScale="1.0"
        android:toYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="false" />
</set>

首先,它应在500毫秒内将图像从1.0缩放到1.2。
然后在500毫秒内将其缩放回1.0。
这是我的使用方式:

Animation firstAnimation = AnimationUtils.loadAnimation(this, R.anim.first_animation);
imgView.startAnimation(firstAnimation);

它进行一个循环,然后完成。
它按比例放大,然后按比例缩小然后停止。

我如何按预期进行这项工作?


您的Java代码中的imgView是什么?
clifgray

Answers:


63

更新:早在2011年9月,一名Android工程师在很大程度上解决了此问题。现在可以使用XML中被忽略的属性,但repeatCount和除外fillEnabled(由于某种原因,它们仍被忽略)。这意味着AnimationSet不幸的是要重复一次仍然不容易。

有关详细信息,请参见更新的文档中的概述(说明哪些属性被忽略,哪些起作用以及哪些传递给子级)。而对于什么更深的理解fillAfterfillBeforefillEnabled实际上做,看工程师的(切特·哈泽)的博客文章关于它在这里


原始答案

为了扩展Pavel和其他人的回答:确实,<set>标签是可笑的越野车。它不能正确处理repeatCount以及其他许多属性。

我花了几个小时弄清楚它可以做什么和不能解决什么,并在此处提交了错误报告/问题:问题17662

总结(这涉及AnimationSets):

setRepeatCount()/ android:repeatCount

此属性(以及repeatMode)在代码或XML中不起作用。这使得很难重复整个动画集。

setDuration()/ android:duration

在代码WORKS中的AnimationSet上进行设置(覆盖子动画的所有持续时间),但在包含在XML的标记中时则不设置

setFillAfter()/ android:fillAfter

该代码在代码和XML中均有效。奇怪的是,我无需设置fillEnabled为true就可以正常工作。

setFillBefore()/ android:fillBefore

似乎在代码和XML中均无效/被忽略

setFillEnabled()/ android:fillEnabled

似乎对代码和XML均无效/被忽略。即使不包括fillEnabled或将fillEnabled设置为false,我仍然可以使fillAfter正常工作。

setStartOffset()/ android:startOffset

这仅适用于代码,而不适用于XML。


48

我发现<set>标记在class AnimationSet类中具有错误的实现。
它不能正确处理repeatCount
我们可以做的-是直接在<scale>标记中设置repeatCount。 这个XML资源运作良好:


<?xml version="1.0" encoding="utf-8"?>
<scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:duration="200"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:toXScale="1.05"
    android:toYScale="1.05"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatMode="reverse"
    android:fillAfter="false"
    android:repeatCount="24"
/>

不幸的是,这一次只限于一个动画。
我们不能以此方式定义动画序列...


我正在一组中运行2个动画,但它们没有给我带来任何问题。请告诉我您正在谈论哪个问题?哪个错误?目前正在开发1.6 sdk
AZ_

在xml中声明repeatCount有效,但在代码中
无效

39

您应该包含该属性

android:repeatCount="infinite"

但是在“比例”动画中而不是在“设置”中


1
但是这些动画会等待上一个动画完成吗?谢谢
filthy_wizard

谢谢,这有效!以编程方式设置它并不是出于任何原因。
樱桃波

谢谢!这工作了。但这是连续的。是否有可能使这种情况每5秒发生一次?
d34th4ck3r

32

为了获得重复的动画,我使用了动画侦听器,并在动画结束时再次调用了动画。这样就可以像对带有方括号的动画一样对照相机进行对焦。

这是动画布局xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
    android:fromXScale="1.0"
    android:toXScale=".7"
    android:fromYScale="1.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toYScale=".7"
    android:duration="1000"/>
<scale 
    android:duration="1000"
    android:fromXScale=".7"
    android:toXScale="1.0"
    android:fromYScale=".7"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toYScale="1.0"
    android:startOffset="1000"/>

</set>

这是java代码

 public void startAnimation() {

            View brackets = findViewById(R.id.brackets);
            brackets.setVisibility(View.VISIBLE);

            Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
            anim.setAnimationListener(new AnimationListener() {

                @Override
                public void onAnimationEnd(Animation arg0) {
                    Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
                    anim.setAnimationListener(this);
                    brackets.startAnimation(anim);

                }

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

                }

                @Override
                public void onAnimationStart(Animation arg0) {
                    // TODO Auto-generated method stub

                }

            });


            brackets.startAnimation(anim);
}

2
雅应该是正确的答案。在所有设备和操作系统级别上工作
Smeet 2015年

它也对我有帮助,但是我从End方法中删除了这两行动画anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this,R.anim.crosshair_focusing); anim.setAnimationListener(this);
阿依达

10

我也面临着同样的问题..我在XMl文件中包含了android:repeatCount =“ infinite” ..现在它的工作正常...

  <translate 
           android:fromXDelta="0"
           android:toXDelta="80"
           android:duration="1000"
           android:repeatCount="infinite"   
           android:repeatMode="reverse" 
           android:pivotX="50%"
           android:pivotY="50%"                             
           android:fillAfter="true"/>


9

您可以尝试此代码。在您的代码中添加

firstAnimation.setRepeatCount(5);

这将在一定时间内重复播放动画

firstAnimation.setRepeatCount(Animation.INFINITE);
firstAnimation.setRepeatMode(Animation.INFINITE);

这将无限期地重复动画。


4
repeatMode应该是RESTARTREVERSE
xinthink

多数民众赞成在正是我想要的,设置为动态设置为无穷大。
Varun Chaudhary


4

我试图使用Daniel的代码来显示动画的确切次数,但遇到一个问题:动画被显示了大约n / 2次,而预期是n次。

所以我修改了Daniel的代码:

//...
@Override
public void onAnimationEnd(Animation arg0) {
    mCurrentCount++;
    if (mCurrentCount < REPEAT_COUNT) {  
        Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
        anim.setAnimationListener(this);
        brackets.post(new Runnable() {
            @Override
            public void run() {
                brackets.startAnimation(anim);
            }
        }  
    } 
}
//... 

使用上面显示的变体,动画显示为REPEAT_COUNT次,因为View.post()方法提供了在完成所有与先前动画相关的动作之后开始新动画的能力。


3

您只需要在我下面建议的xml代码中添加一行即可。

<scale
    android:duration="500"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:toXScale="1.2"
    android:toYScale="1.2"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite" // just add this one line 
    android:fillAfter="false"
    />
</set>


2

将以下类添加到您的项目中:

import android.view.View;
import android.view.animation.Animation;

public class AnimationRepeater implements Animation.AnimationListener
{
    private View view;
    private Animation animation;
    private int count;

    public AnimationRepeater(View view, Animation animation)
    {
        this.view = view;
        this.animation = animation;
        this.count = -1;
    }

    public AnimationRepeater(View view, Animation animation, int count)
    {
        this.view = view;
        this.animation = animation;
        this.count = count;
    }

    public void start()
    {
        this.view.startAnimation(this.animation);
        this.animation.setAnimationListener(this);
    }

    @Override
    public void onAnimationStart(Animation animation) { }

    @Override
    public void onAnimationEnd(Animation animation)
    {
        if (this.count == -1)
            this.view.startAnimation(animation);
        else
        {
            if (count - 1 >= 0)
            {
                this.animation.start();
                count --;
            }
        }
    }

    @Override
    public void onAnimationRepeat(Animation animation) { }
}

为了使视图无限循环,请执行以下操作:

Animation a = AnimationUtils(Context, R.anim.animation);
new AnimationRepeater(View, a).start();

如果只想重复N次动画,请执行以下操作:

Animation a = AnimationUtils(Context, R.anim.animation);
new AnimationRepeater(View, a, int N).start();

N代表重复次数。


2

android:repeatMode="reverse"在项目中使用before解决了这个问题。

<scale
    android:interpolator="@android:anim/decelerate_interpolator"
    android:duration="500"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:toXScale="1.2"
    android:toYScale="1.2"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatMode="reverse"
    android:repeatCount="infinite" />

1

我会以编程方式完成大部分工作,但是我可能迟到或效率低下,但这确实达到了重复的animationset目标(我什至有2个交替的动画集)。这些代码所做的只是在一个图像中淡入淡出,然后暂停,然后淡出,在另一图像中淡入淡出,暂停,淡出,然后返回第一个(漂洗并重复)。我首先定义了Imageviews:

    final ImageView purple = (ImageView)findViewById(R.id.purp);
    final ImageView yellow = (ImageView)findViewById(R.id.yell);
    purple.setVisibility(View.INVISIBLE);
    yellow.setVisibility(View.INVISIBLE);

然后,我制作了两个计时器,任务计时器和处理程序,以处理何时开始和停止每个动画:

    Timer p = new Timer();
    TimerTask pu = new TimerTask() {
        public void run() {
                handler1.post(new Runnable() {
                        public void run() 
                        {
                           fadein(purple);
                        }
               });
        }};
        p.schedule(pu, 6000, 12000);

    final Handler handler2 = new Handler();

    Timer y = new Timer();
    TimerTask ye = new TimerTask() {
        public void run() {
                handler2.post(new Runnable() {
                        public void run() 
                        {
                           fadein(yellow);
                        }
               });
        }};

        y.schedule(ye, 0, 12000);

最后,我只是通过动画侦听器来确定何时开始每个动画,而不是通过添加动画来创建动画集:

public void fadein (final ImageView image)
{
    Animation anim = new AlphaAnimation(0, 1);

    anim.setDuration(2000);

    image.startAnimation(anim);
    anim.setAnimationListener(new AnimationListener() {
        public void onAnimationEnd(Animation animation) 
        {
            image.clearAnimation();
            image.invalidate();
            pause(image);

        }

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

        }

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

        }
    });
}    
public void pause (final ImageView image)
{
    Animation anim = new AlphaAnimation(1, 1);

    anim.setDuration(2000);

    image.startAnimation(anim);
    anim.setAnimationListener(new AnimationListener() {
        public void onAnimationEnd(Animation animation) 
        {
            image.clearAnimation();
            image.invalidate();
            fadeout(image);

        }

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

        }

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

        }
    });
}     
public void fadeout (final ImageView image)
{
    Animation anim = new AlphaAnimation(1,0);

    anim.setDuration(2000);

    image.startAnimation(anim);
    anim.setAnimationListener(new AnimationListener() {
        public void onAnimationEnd(Animation animation) 
        {
            image.clearAnimation();
            image.invalidate();
        }

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

        }

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

        }
    });
}    

清除动画并使以前的尝试无效并使此事情正常工作。我不知道是否需要它们。

希望这对某人有帮助。


瑞安


1

我得到了这个...我试图使视图连续旋转一圈。

以前我使用了rotation.setRepeatMode(-1),但是没有用。切换到setrepeatcount,它可以工作。这是在软糖4.2.2

 ObjectAnimator rotation = ObjectAnimator.ofFloat(myview,
                          "rotation", 360).setDuration(2000);
                rotation.setRepeatMode(-1);
          rotation.setRepeatCount(Animation.INFINITE); 
 rotation.start();

0

我也遇到过同样的问题,但是由于UI线程有时可能很忙,所以不想在Java中执行任何计时操作。INFINITE标志不适用于set标签。因此,我用一小段代码解决了这个问题:

mAnimation = (AnimationSet) AnimationUtils.loadAnimation(myContext, R.anim.blink);
mIcon.startAnimation(mAnimation);
mAnimation.setAnimationListener(new AnimationListener() {
    public void onAnimationStart(Animation animation) {}
    public void onAnimationRepeat(Animation animation) {}
    public void onAnimationEnd(Animation animation) {
        mIcon.startAnimation(mAnimation);
    }
});

使用以下XML:

<alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="0.0"
    android:toAlpha="1.0" />

<alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="0.9"
    android:startOffset="1000"
    android:toAlpha="0.0" />

mIcon是我的布局中的ImageView。


0

我已经解决了这个问题。这是我的修订版本:

public class HelloAndroidActivity extends Activity {
private static String TAG = "animTest";
private Animation scaleAnimation;
private int currentCover = 0;
private List<ImageView> imageViews = new ArrayList<ImageView>(3);
private Button btn;
private ImageView img;

/**
 * Called when the activity is first created.
 * @param savedInstanceState If the activity is being re-initialized after 
 * previously being shut down then this Bundle contains the data it most 
 * recently supplied in onSaveInstanceState(Bundle). <b>Note: Otherwise it is null.</b>
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i(TAG, "onCreate");
    setContentView(R.layout.test);

    img = (ImageView)findViewById(R.id.testpict);
    imageViews.add(img);
    img = (ImageView)findViewById(R.id.testpictTwo);
    imageViews.add(img);
    img = (ImageView)findViewById(R.id.testpict3);
    imageViews.add(img);

    scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.photo_scale);
    scaleAnimation.setAnimationListener(new CyclicAnimationListener());

    btn = (Button)findViewById(R.id.startBtn);
    btn.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            imageViews.get(0).startAnimation(scaleAnimation);
        }
    });



}

private class CyclicAnimationListener implements AnimationListener{

    @Override
    public void onAnimationEnd(Animation animation) {
        currentCover += 1;
        if(currentCover >= imageViews.size()){
            currentCover = 0;
        }
        img = imageViews.get(currentCover);
        scaleAnimation = AnimationUtils.loadAnimation(HelloAndroidActivity.this, R.anim.photo_scale);
        scaleAnimation.setAnimationListener(new CyclicAnimationListener());
        img.startAnimation(scaleAnimation);
    }

    @Override
    public void onAnimationRepeat(Animation animation) {
        Log.d("Animation", "Repeat");
    }

    @Override
    public void onAnimationStart(Animation animation) {

    }

}

}

0

我在使用向后兼容的应用程序时遇到了这个问题。太令人沮丧了!我最终编写了一个不错的解决方法类,可以从onCreate调用它,并将任何动画资源启动为不确定的循环。

可以在以下位置找到该类:AnimationLooper:https//gist.github.com/2018678


0

在研究了互联网上的答案之后,我找到了一个非常适合我的解决方案。(是的,当与animationSet一起使用时,repeatCount和repeatMode的bug很大)。

anim_rotate_fade.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:ordering="together" >

    <objectAnimator
        android:duration="3000"
        android:propertyName="rotation"
        android:repeatCount="1"
        android:valueTo="360"
        android:valueType="floatType" />

    <objectAnimator
        android:duration="3000"
        android:propertyName="alpha"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:valueFrom="0.0"
        android:valueTo="0.3"
        android:valueType="floatType" />

    <objectAnimator
        android:duration="3000"
        android:propertyName="y"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:valueFrom="380"
        android:valueTo="430"
        android:valueType="floatType" />

</set>

活动中:(通过在动画结束后稍加延迟来解决)。

ImageView starlightImageView = new ImageView(this);
starlightImageView.setImageResource(R.drawable.starlight);
final AnimatorSet animate = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.anim.anim_rotate_fade);
AnimatorListenerAdapter animatorListener = new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        new Handler().postDelayed(new Runnable() {
            @Override public void run() {
                animate.start();
            }
        }, 1000);
    }
};
animate.setTarget(starlightImageView);
animate.addListener(animatorListener);

您想研究很多类,但是目前我正在使用高度灵活的objectAnimator。我不建议使用Animation或AnimationUtils:

  • 动画
  • AnimationUtils
  • 动画师
  • AnimatorInflater
  • AnimatorListener
  • AnimatorListenerAdapter


0

对@Danufr答案稍作调整,以节省再次加载资源的时间。

    operator = (ImageView) findViewById(R.id.operator_loading);
  final  Animation ani = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.finding_operator);


    ani.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {

            operator.startAnimation(ani);

        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

    operator.setAnimation(ani);

0

我使用线程解决了这个问题。

Button btn = (Button) findViewById(R.id.buttonpush);
    final TextView textview = (TextView) findViewById(R.id.hello);
    btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            textview.setText("...................");
            final Animation animationtest = AnimationUtils.loadAnimation(MainActivity.this, android.R.anim.slide_in_left);
            animationtest.setDuration(1000);

            final Handler handler = new Handler();
            Runnable runnable = new Runnable() {
                public void run() {
                    handler.postDelayed(this, 1500);
                    textview.startAnimation(animationtest);
                }
            };
            handler.postDelayed(runnable, 500); // start
            handler.removeCallbacks(runnable); //STOP Timer

        }
    });


0

在我的情况下,以上解决方案均无效。Danuofr的解决方案确实适用于动画设置,但是当我进行单元测试时,我的测试曾经陷入无限循环。最后,针对我的情况,我需要重复此动画特定的次数。因此,我以级联的方式在anim_rot.xml中手动添加了动画副本,并添加了offset值。我知道这很糟糕,不会对很多人有用,但这是我的案例的唯一解决方法。

anim_rot.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:duration="2000"
        android:fromDegrees="20"
        android:pivotX="29%"
        android:pivotY="50%"
        android:toDegrees="-20" />
    <rotate
        android:duration="2000"
        android:fromDegrees="-20"
        android:pivotX="29%"
        android:pivotY="53%"
        android:startOffset="2000"
        android:toDegrees="20" />
    <rotate
        android:startOffset="4000"
        android:duration="2000"
        android:fromDegrees="20"
        android:pivotX="29%"
        android:pivotY="56%"
        android:toDegrees="-20" />
    <rotate
        android:duration="2000"
        android:fromDegrees="-20"
        android:pivotX="29%"
        android:pivotY="59%"
        android:startOffset="6000"
        android:toDegrees="20" />
    <rotate
        android:startOffset="8000"
        android:duration="2000"
        android:fromDegrees="20"
        android:pivotX="29%"
        android:pivotY="62%"
        android:toDegrees="-20" />
    <rotate
        android:duration="2000"
        android:fromDegrees="-20"
        android:pivotX="29%"
        android:pivotY="65%"
        android:startOffset="10000"
        android:toDegrees="20" />
</set>

我这样做是为了重复动画3次。您可以通过添加偏移值来添加更多副本以在特定时间重复该操作。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.