Android animation does not repeat

后端 未结 23 1355
囚心锁ツ
囚心锁ツ 2020-11-27 14:01

I\'m trying to make simple animation that would repeat several times (or infinitely).
It seems that android:repeatCount does not work!
Here is my anim

相关标签:
23条回答
  • 2020-11-27 14:10

    After researching through the answers from internet, I found a solutions which works perfectly for me. (And yes, the repeatCount and repeatMode is extremely buggy when used together with animationSet).

    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>
    

    In activity: (Solve it by introducing a slight delay after animation ended).

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

    There are a lot of classes you would like to research on, but currently I'm using objectAnimator which is highly flexible. I wouldn't recommend to use Animation or AnimationUtils:

    • Animation
    • AnimationUtils
    • Animator
    • AnimatorInflater
    • AnimatorListener
    • AnimatorListenerAdapter
    0 讨论(0)
  • 2020-11-27 14:11

    Update: Back in Sep, 2011 an Android engineer fixed this issue for the most part. The attributes that were ignored in XML now work, with the exception of repeatCount and fillEnabled which are still ignored (on purpose for some reason). This means it still isn't easy to repeat an AnimationSet unfortunately.

    For details please see the overview in the updated docs (explains which attributes are ignored, which work, and which are passed onto children). And for a deeper understanding of what fillAfter, fillBefore, and fillEnabled actually do, see the engineer's (Chet Haase) blog post about it here.


    Original Answer

    To expand upon answers by Pavel and others: it is true that the <set> tag is ridiculously buggy. It can't deal correctly with repeatCount and a number of other attributes.

    I spent a few hours figuring out what it can and can't deal with and have submitted a bug report/issue here: Issue 17662

    In summary (this concerns AnimationSets):

    setRepeatCount() / android:repeatCount

    This attribute (as well as repeatMode) does not work in code or XML. This makes repeating an entire set of animations difficult.

    setDuration() / android:duration

    Setting this on an AnimationSet in code WORKS (overrides all durations of children animations), but not when included in the tag in XML

    setFillAfter() / android:fillAfter

    This works in both code and XML for the tag. Strangely I have gotten it to also work without the need to set fillEnabled to true.

    setFillBefore() / android:fillBefore

    Seems to have no effect/ignored in both code and XML

    setFillEnabled() / android:fillEnabled

    Seems to have no effect/ignored in both code and XML. I can still get fillAfter to work even without including fillEnabled or setting fillEnabled to false.

    setStartOffset() / android:startOffset

    This works only in code and not XML.

    0 讨论(0)
  • 2020-11-27 14:11

    I've found that <set> tag has buggy implementation in class AnimationSet.
    It can't deal correctly with repeatCount.
    What we can do - is to set repeatCount directly in <scale> tag.

    This XML resource is working well:

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

    Unfortunately, this is limited to only one animation at once.
    We can not define a sequence of animations this way...

    0 讨论(0)
  • 2020-11-27 14:12

    I tried to use Daniel's code to show animation exact number of times and had a problem: animation was shown approximatily n / 2 times, when n times expected.

    So I have modified Daniel's code:

    //...
    @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);
                }
            }  
        } 
    }
    //... 
    

    Using variant, shown above, animation is shown exectly REPEAT_COUNT times, because View.post() method gives an ability to start new animation after finishing all actions, related with previous animation.

    0 讨论(0)
  • 2020-11-27 14:12

    I solved this problem using android:repeatMode="reverse" before in my project.

    <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" />
    
    0 讨论(0)
  • 2020-11-27 14:13

    I've solved this problem. This is my version of the fix:

    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 讨论(0)
提交回复
热议问题