Android动画不重复

时间:2010-12-18 23:04:34

标签: android animation

我正在尝试制作可以重复几次(或无限次)的简单动画 似乎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);

它进行一个循环然后结束。
它会向上扩展,然后按比例缩小然后停止
如何按预期方式开展此工作?

23 个答案:

答案 0 :(得分:62)

更新:早在2011年9月,一位Android工程师在很大程度上解决了这个问题。 XML中被忽略的属性现在可以工作,但repeatCountfillEnabled除外,它们仍被忽略(出于某种原因故意)。这意味着遗憾的是,重复AnimationSet仍然不容易。

有关详细信息,请参阅updated docs中的概述(解释忽略哪些属性,哪些属性有效,哪些属性传递给子级)。要更深入地了解fillAfterfillBeforefillEnabled实际执行的操作,请参阅工程师(Chet Haase)关于它的博客文章here


原始答案

为了扩展Pavel和其他人的答案:<set>标签确实是一个荒谬的错误。它无法正确处理repeatCount和其他一些属性。

我花了几个小时搞清楚它能做什么和不能处理什么,并在这里提交了一个错误报告/问题:Issue 17662

总结(这涉及AnimationSet s):

  

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。

  

答案 1 :(得分:42)

我发现&lt; set&gt; 标记在 AnimationSet 类中有错误的实现。
它无法正确处理 repeatCount 我们可以做的是直接在&lt; scale&gt; 标记中设置 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 :(得分:38)

您应该包含属性

android:repeatCount="infinite"

但是在你的“比例”动画中没有“设置”

答案 3 :(得分:31)

要获得重复动画,我使用了动画侦听器,并在结束时再次调用动画。这样就可以像带有括号的动画一样聚焦相机标线。

这是动画布局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);
}

答案 4 :(得分: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"/>

答案 5 :(得分:8)

你可以试试这段代码。 在您的代码中添加,

firstAnimation.setRepeatCount(5);

这将重复动画一段时间

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

这会无限期地重复动画。

答案 6 :(得分:2)

你必须在我下面建议的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>

答案 7 :(得分: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代表重复次数。

答案 8 :(得分:2)

使用android sdk版本4.0.3:

在给定的动画元素中:

机器人:repeatCount = “ - 1”

使它成为无限动画。

答案 9 :(得分:2)

我尝试使用Daniel的代码来显示动画的确切次数并遇到问题:当预期n次时,动画显示近似n / 2次。

所以我修改了丹尼尔的代码:

//...
@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()方法可以在完成与上一个动画相关的所有动作后启动新动画。

答案 10 :(得分: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();

答案 11 :(得分:1)

我以编程方式完成了我的大部分工作,但是我可能会迟到或效率低但是这个但是我完成了重复动画集目标(我甚至有2个交替的动画集)。所有这些代码都只是淡入一个图像,暂停,然后淡出,淡入另一个图像,暂停,淡出,并带回第一个(冲洗和重复)。我首先定义了我的Imageview:

    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

        }
    });
}    

清除并使之前的尝试无效,并让这件事正常工作。我不知道他们是否需要。

希望这有助于某人。


赖安

答案 12 :(得分:1)

我在项目中使用reverse解决了这个问题。

<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" />

答案 13 :(得分:0)

我在处理向后兼容的应用时遇到了这个问题。真令人沮丧!我最终编写了一个很好的解决方法类,可以从onCreate调用,并将任何动画资源启动到一个无限循环。

这个类,AnimationLooper,可以在这里找到: https://gist.github.com/2018678

答案 14 :(得分: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) {

    }

}

}

答案 15 :(得分: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。

答案 16 :(得分:0)

通过对互联网的回答进行研究后,我找到了一个适合我的解决方案。 (是的,当与animationSet一起使用时,repeatCount和repeatMode非常错误。)

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

答案 17 :(得分:0)

需要先监听第一个动画的完成情况,然后在onStopAnimation回调中重新启动动画,试试这个link

答案 18 :(得分: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);

答案 19 :(得分: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

        }
    });

答案 20 :(得分:0)

它工作正常

 GifDrawable gifDrawable = (GifDrawable) gifImageView.getDrawable();
    gifDrawable.setLoopCount(0);

答案 21 :(得分:0)

以上解决方案均无法解决我的问题。 Danuofr的解决方案确实适用于动画集,但是当我进行单元测试时,我的测试过去常常陷入无限循环。最后,具体到我的情况,我需要重复这个动画特定的次数。所以,我手动在anim_rot.xml中以级联的方式添加我的动画副本添加偏移值。我知道它很糟糕并且不会为许多人工作,但这是我案件的唯一解决方法。

anim_rot.xml

restTemplate.postForObject(apiUri.toString(), command, BigDecimal.class);

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

答案 22 :(得分:-1)

尝试将代码添加到循环线程或while / for语句