The cause of

Recently, I was working on a package for component-based framework, and now I have developed some packages for common tool classes. Suddenly, I realized that there is no animation tool class, so I started to develop it.

Train of thought

Since to do animation, it must be to do attribute the encapsulation of animation tools, because the complement between animation and frame by frame animation does not change target animation theme of real property, during the development of Android has less and less people to do with these two animation framework is developed, and the properties of animation is relatively more and more widely used in the development process, So this time the tool class encapsulation, only for the property animation encapsulation.

The corresponding class of attribute animation is called ObjectAnimator. It is mainly used to implement some basic Settings of animation. I will not write the specific use of this class, but interested friends can learn the relevant knowledge of attribute animation.

The encapsulation of the property animation tool class inevitably takes into account the need for property animation to be played in combination, and there are about three ways to play property animation in combination:

AnimatorSet Builder is an animation tool class that makes it easy to add animations to an AnimatorSet and to set relationships between animations. After (long), after(Animator), before(Animator), and with(Animator) methods are declared in animatorSet. Builder.

  • After (delay) Sets the animation delay
  • After (anim) Sets the animation to play after the anim animation ends
  • Before (anim) Sets this animation to play before anim
  • With (anim) Sets this animation to play with anim

The paly(anim) method is then called to chain the animation

AnimatorSet set=new AnimatorSet();
set.play(anim1).before(anim2).with(anim3).after(anim4);
Copy the code

We notice that he executes after first, then play and with together, and finally before. So remember this order, no matter how you write it, this is the order of execution.

2. Use playSequentially of AnimatorSet

API

PlaySequentially (List items) : Add a set of animations that play playSequentially(Animator… Items) : Adds a group of animations to be played one by one

AnimatorSet bouncer = new AnimatorSet();
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_TRANSLATION_X, 0f.300f);
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_TRANSLATION_Y, 0f.300f);
ObjectAnimator objectAnimatorC = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_ROTATION, 0f.360f);

bouncer.playSequentially(objectAnimatorA, objectAnimatorB, objectAnimatorC);

bouncer.setDuration(6000);
bouncer.start();
Copy the code

3. Use AnimatorSet’s palyTogether

API

PlayTogether (Collection items) : Add a group of animations. PlayTogether (Animator… Items) : Adds a group of animations to be played together

AnimatorSet bouncer = new AnimatorSet();
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_TRANSLATION_X, 0f.300f);
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_TRANSLATION_Y, 0f.300f);
ObjectAnimator objectAnimatorC = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_ROTATION, 0f.360f);

bouncer.playSequentially(objectAnimatorA, objectAnimatorB, objectAnimatorC);

bouncer.setDuration(6000);
bouncer.start();
Copy the code

The implementation method is how to call play,playSequentially, and playTogether. This method requires a reasonable encapsulation.

Each ObjectAnimator has three interfaces for the listener interface encapsulation:

  • Animator. AnimatorListener life cycle for the entire animation listening in

    anim.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                Toast.makeText(MainActivity.this."start", Toast.LENGTH_LONG).show();
            }
    
            @Override
            public void onAnimationEnd(Animator animator) {
                Toast.makeText(MainActivity.this."End", Toast.LENGTH_LONG).show();
            }
    
            @Override
            public void onAnimationCancel(Animator animator) {
                Toast.makeText(MainActivity.this."Cancel", Toast.LENGTH_LONG).show();
            }
    
            @Override
            public void onAnimationRepeat(Animator animator) {
                Toast.makeText(MainActivity.this."rapeat", Toast.LENGTH_LONG).show(); }}); anim.start();Copy the code
  • ValueAnimator. AnimatorUpdateListener listening for the animation frame by frame

    ValueAnimator vanim = ValueAnimator.ofInt(0.10.20);
        vanim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
    
       // If ValueAnimtor specifies the I of Int, then ValueAnimtor will return the Value of Int.That is, the return value type is the same as the type you createdint value = (int) valueAnimator.getAnimatedValue(); }});Copy the code
  • Animator. AnimatorPauseListener pause and play about the animation listening in

    new Animator.AnimatorPauseListener() {
                @Override
                public void onAnimationPause(Animator animator) {}@Override
                public void onAnimationResume(Animator animator) {}}Copy the code

    Because of my initial idea is to use the builder pattern chain invocation pattern to design my tools, if according to the general method and the whole monitor interface Settings will be disastrous, because all listening in the setting of the interface is chaotic, so must deal with here, my train of thought is that learning SpringSecurity chain call design, Set your own classes for each type of listening, and then let the tool main class call this type of monitoring interface, and then set to end, through the monitoring interface class and type of main () method returned to tools, so that when the chain calls have a start-stop order, not chaos performed, and if it’s not set up to monitor, Not calling the listener class setting also does not affect the execution of the main class.

    Intercept key code, using the Play method’s listening interface Settings as an example:

    /** * The main tool class **/
    public static class AnimatorSetWrap{
         PlayAnimationListener playListener;
         public PlayAnimationListener toAddPlayListener(a){
                playListener=new PlayAnimationListener(this);
                returnplayListener; }}/** * Play method corresponding ObjectAnimator listening instance */
        public static class PlayAnimationListener implements IAnimatorListener<PlayAnimationListener>{
    
            private  Animator.AnimatorListener animatorListener;
            private ValueAnimator.AnimatorUpdateListener updateListener;
            private Animator.AnimatorPauseListener pauseListener;
    
            public AnimatorSetWrap animatorSetWrap;
            public  PlayAnimationListener(AnimatorSetWrap animatorSetWrap){
                    this.animatorSetWrap=animatorSetWrap;
            }
            @Override
            public PlayAnimationListener setAnimatorListener(Animator.AnimatorListener animatorListener) {
                this.animatorListener=animatorListener;
                return this;
            }
    
            @Override
            public PlayAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener animatorListener) {
                this.updateListener=animatorListener;
                return this;
            }
    
            @Override
            public PlayAnimationListener setPauseListener(Animator.AnimatorPauseListener animatorListener) {
                this.pauseListener=animatorListener;
                return this;
            }
            @Override
            public AnimatorSetWrap and(a){
                returnanimatorSetWrap; }}/** * Public template interface * for animation listening@param <T>
         */
        interface IAnimatorListener<T>{
            /** * Set the AnimatorListener method *@param listener
             * @return* /
            T setAnimatorListener(Animator.AnimatorListener listener);
    
            /** * The AnimatorUpdateListener method *@param listener
             * @return* /
            T setUpdateListener(ValueAnimator.AnimatorUpdateListener listener);
    
            /** * The AnimatorPauseListener method *@param listener
             * @return* /
            T setPauseListener(Animator.AnimatorPauseListener listener);
    
            /** * Bridge the animation listener to the animation tool class@return* /
            AnimatorSetWrap and(a);
        }
    Copy the code

    Specific use method:

    AnimatorUtil.AnimatorSetWrap  animatorSetWrapDemo=new AnimatorSetWrap().toAddPlayListener().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    LogUtils.e("Values."+valueAnimator.getAnimatedValue());
                }
            }).and();
    Copy the code

    With this chaining invocation, once the and() method is called, we are back in the instance of the AnimatorSetWrap utility class, and we can continue to call the other animation methods and play the animation.

    code

    Having said so much, I will share my tool class code with you, it may not be perfect, what questions we discuss together:

    import android.animation.Animator;
    import android.animation.AnimatorSet;
    import android.animation.ObjectAnimator;
    import android.animation.TimeInterpolator;
    import android.animation.ValueAnimator;
    import android.os.Build;
    import android.support.annotation.Nullable;
    import android.support.annotation.Size;
    import android.view.View;
    import android.view.animation.LinearInterpolator;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /** * Animation tools *@package com.dhcc.commonutils
     *@author jasoncool
     *@createDate2018/11/20 company *@description* * /
    public class AnimatorUtils {
    
        public static final String ALPHA="Alpha";
        public static final String TRANSX="TranslationX";
        public static final String TRANSY="TranslationY";
        public static final String SCALEX="ScaleX";
        public static final String SCALEY="ScaleY";
        public static final String ROTATION="Rotation";
        public static final String ROTATIONX="RotationX";
        public static final String ROTATIONY="RotationY";
    
        /** * Default TimeInterpolator, interpolate front and rear deceleration, interpolate middle acceleration */
        private static final TimeInterpolator sDefaultInterpolator =
                new LinearInterpolator();
    
        public static AnimatorSetWrap createAnimator(a) {
            return new AnimatorSetWrap();
        }
    
        / * * *@paramInterpolator Default TimeInterpolator *@return* /
        public static AnimatorSetWrap createAnimator(TimeInterpolator interpolator) {
            return new AnimatorSetWrap(interpolator);
        }
    
        /** * Attribute animation group * attribute animation group corresponds to the AnimatorSet class, we just need to new it. * * It mainly corresponds to the four methods, play, before, with, after. * These four methods are all animator classes filled in at the end, but executed in different order, corresponding to start, sync, and start. * We notice that he executes after first, then play and with together, and finally before. * So remember this order, no matter how you write it, this is the order of execution. * * /
        public static class AnimatorSetWrap{
    
            private View mView;
            /** * The default interpolator that comes with the tool class when no default interpolator is set
            private TimeInterpolator mTimeInterpolator;
            /** * The play method is allowed to execute only once
            boolean mIsPlaying=false;
            /** * The animation container for the joint animation */
            private AnimatorSet mAnimatorSet;
            /** * The animation constructor for the joint animation */
            private AnimatorSet.Builder mAnimatorBuilder;
            /** * Default execution time */
            private int mDuration=1000;
            /** * play listener class */
            PlayAnimationListener playListener;
            /** * before listener class */
            BeforeAnimationListener beforeListener;
            /** * with listener class */
            WithAnimationListener withListener;
            /** * after listener class */
            AfterAnimationListener afterListener;
            /** * then listener class */
            ThenAnimationListener thenListener;
            /** * A list container that stores animations when played sequentially or simultaneously */
            List<Animator> mAnimatorList;
            /** * If the then animation has been initialized */
            boolean mHasInitThenAnim=false;
    
            private AnimatorSetWrap(a){
              this(sDefaultInterpolator);
            }
    
            /** * constructor * is mainly responsible for * 1. Initialize the default interpolator mTimeInterpolator * 2. Initialize the joint animation Set mAnimatorSet * 3. Initialize the animation container mAnimatorList * in sequence or simultaneously@param interpolator
             */
            private AnimatorSetWrap(TimeInterpolator interpolator) {
                mTimeInterpolator = interpolator;
                mAnimatorSet = new AnimatorSet();
                mAnimatorList=new ArrayList<>(16);
            }
    
            /** * This method is called first to listen on the Play animation@return* /
            public PlayAnimationListener toAddPlayListener(a){
                playListener=new PlayAnimationListener(this);
                return playListener;
            }
            /** * This method is called to listen on the Before animation@return* /
            public BeforeAnimationListener toAddBeforeListener(a){
                beforeListener=new BeforeAnimationListener(this);
                return beforeListener;
            }
            /** * this method is called if you want to listen on the With animation@return* /
            public WithAnimationListener toAddWithListener(a){
                withListener=new WithAnimationListener(this);
                return withListener;
            }
            /** * Call this method if you want to listen on the After animation@return* /
            public AfterAnimationListener toAddAfterListener(a){
                afterListener=new AfterAnimationListener(this);
                return afterListener;
            }
    
            /** * The method that listens for sequential or simultaneous animation execution * is called before the Then method *@return* /
            public ThenAnimationListener toAddThenListener(a){
                thenListener=new ThenAnimationListener(this);
                return thenListener;
            }
    
            /** * The method called when the animations are played sequentially or simultaneously generates an Animator within it and adds the Animator to the mAnimatorList for use *@paramView animation execution body view *@paramAnimName Animation type *@paramInterpolator Animation interpolator uses the default * if not set@paramRepeatCount Number of repeats *@paramDuration Execution time *@paramValues Specifies the animation execution value *@return* /
            public AnimatorSetWrap then(View view, String animName, @Nullable TimeInterpolator interpolator, @Size(min = 0,max=Integer.MAX_VALUE) int repeatCount, @Size(min = 0,max=Integer.MAX_VALUE) int duration, float. values){
                LogUtils.e("addThen");
                if(view==null) {throw new RuntimeException("View cannot be empty");
                }
                mIsPlaying = true;
                mView = view;
                ObjectAnimator thenAnimator = ObjectAnimator.ofFloat(view,animName,values);
                thenAnimator.setInterpolator(interpolator==null? mTimeInterpolator:interpolator); thenAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
                thenAnimator.setDuration(duration<0? mDuration:duration);if(thenListener! =null&&thenListener.animatorListener ! =null) {
                    thenAnimator.addListener(thenListener.animatorListener);
                }
                if(thenListener! =null&&thenListener.updateListener! =null){
                    thenAnimator.addUpdateListener(thenListener.updateListener);
                }
                if(thenListener! =null&&thenListener.pauseListener! =null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        thenAnimator.addPauseListener(thenListener.pauseListener);
                    }else{
                        throw new RuntimeException("SDK minimum requirement 19");
                    }
                }
                mAnimatorList.add(thenAnimator);
                return this;
            }
    
            public AnimatorSetWrap then(Animator animator) {
                mAnimatorList.add(animator);
                return this;
            }
    
            public AnimatorSetWrap then(AnimatorSetWrap animator) {
                mAnimatorList.add(animator.getAnimatorSet());
                return this;
            }
    
            /** * The entire animation process can only be called once * and the Play method will clear the mAnimatorList of stored sequential or simultaneous method instances *@paramView method body *@paramAnimName Animation type *@paramInterpolator *@paramRepeatCount Number of repeats *@paramDuration Animation duration *@paramValues Animation execution value *@return* /
            public AnimatorSetWrap play(View view, String animName, @Nullable TimeInterpolator interpolator, @Size(min = 0,max=Integer.MAX_VALUE) int repeatCount, @Size(min = 0,max=Integer.MAX_VALUE) int duration, float. values){
                LogUtils.e("play");
                if(mIsPlaying){
                    throw new RuntimeException("The animatorSetwrap.play () method can only be called once");
                }
                if(view==null) {throw new RuntimeException("View cannot be empty");
                }
                mIsPlaying = true;
                mView = view;
                ObjectAnimator playAnimator = ObjectAnimator.ofFloat(view,animName,values);
                playAnimator.setInterpolator(interpolator==null? mTimeInterpolator:interpolator); playAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
                playAnimator.setDuration(duration<0? mDuration:duration);if(playListener! =null&&playListener.animatorListener ! =null) {
                    playAnimator.addListener(playListener.animatorListener);
                }
                if(playListener! =null&&playListener.updateListener! =null){
                    playAnimator.addUpdateListener(playListener.updateListener);
                }
                if(playListener! =null&&playListener.pauseListener! =null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        playAnimator.addPauseListener(playListener.pauseListener);
                    }else{
                        throw new RuntimeException("SDK minimum requirement 19");
                    }
                }
                mAnimatorList.clear();
                mAnimatorBuilder=mAnimatorSet.play(playAnimator);
                return this;
            }
    
            public AnimatorSetWrap play(Animator animator) {
                mAnimatorList.clear();
                mAnimatorBuilder = mAnimatorSet.play(animator);
                return this;
            }
    
            public AnimatorSetWrap play(AnimatorSetWrap animator) {
                mAnimatorList.clear();
                mAnimatorBuilder = mAnimatorSet.play(animator.getAnimatorSet());
                return this;
            }
    
            /** * AnimatorSet Before method *@paramView animation execution body view *@paramAnimName Animation type *@paramInterpolator *@paramRepeatCount Number of repeats *@paramDuration Animation execution duration *@paramValues Animation execution value *@return* /
            public AnimatorSetWrap before(View view, String animName,@Nullable TimeInterpolator interpolator, @Size(min = 0,max=Integer.MAX_VALUE)  int repeatCount,@Size(min = 0,max=Integer.MAX_VALUE)int duration, float. values){
                LogUtils.e("before");
                if(view==null) {throw new RuntimeException("View cannot be empty");
                }
                ObjectAnimator beforeAnimator = ObjectAnimator.ofFloat(view,
                        animName, values).setDuration(duration);
                beforeAnimator.setInterpolator(interpolator==null? mTimeInterpolator:interpolator); beforeAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
                beforeAnimator.setDuration(duration<0? mDuration:duration);if(beforeListener! =null&&beforeListener.animatorListener ! =null) {
                    beforeAnimator.addListener(beforeListener.animatorListener);
                }
                if(beforeListener! =null&&beforeListener.updateListener! =null){
                    beforeAnimator.addUpdateListener(beforeListener.updateListener);
                }
                if(beforeListener! =null&&beforeListener.pauseListener! =null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        beforeAnimator.addPauseListener(beforeListener.pauseListener);
                    }else{
                        throw new RuntimeException("SDK minimum requirement 19");
                    }
                }
                mAnimatorBuilder = mAnimatorBuilder.before(beforeAnimator);
                return this;
            }
    
            public AnimatorSetWrap before(Animator animator) {
                mAnimatorBuilder = mAnimatorBuilder.before(animator);
                return this;
            }
    
            public AnimatorSetWrap before(AnimatorSetWrap animator) {
                mAnimatorBuilder = mAnimatorBuilder.before(animator.getAnimatorSet());
                return this;
            }
    
    
            public AnimatorSetWrap with(View view, String animName,@Nullable TimeInterpolator interpolator,@Size(min = 0,max=Integer.MAX_VALUE) int repeatCount,@Size(min = 0,max=Integer.MAX_VALUE)int duration, float. values){
                LogUtils.e("with");
                if(view==null) {throw new RuntimeException("View cannot be empty");
                }
                ObjectAnimator withAnimator = ObjectAnimator.ofFloat(view,
                        animName, values).setDuration(duration);
                withAnimator.setInterpolator(interpolator==null? mTimeInterpolator:interpolator); withAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
                withAnimator.setDuration(duration<0? mDuration:duration);if(withListener! =null&&withListener.animatorListener ! =null) {
                    withAnimator.addListener(withListener.animatorListener);
                }
                if(withListener! =null&&withListener.updateListener! =null){
                    withAnimator.addUpdateListener(withListener.updateListener);
                }
                if(withListener! =null&&withListener.pauseListener! =null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        withAnimator.addPauseListener(withListener.pauseListener);
                    }else{
                        throw new RuntimeException("SDK minimum requirement 19");
                    }
                }
                mAnimatorBuilder = mAnimatorBuilder.with(withAnimator);
                return this;
            }
    
            public AnimatorSetWrap with(Animator animator) {
                mAnimatorBuilder = mAnimatorBuilder.with(animator);
                return this;
            }
    
            public AnimatorSetWrap with(AnimatorSetWrap animator) {
                mAnimatorBuilder = mAnimatorBuilder.with(animator.getAnimatorSet());
                return this;
            }
    
    
    
            public AnimatorSetWrap after(View view, String animName,@Nullable TimeInterpolator interpolator,@Size(min = 0,max=Integer.MAX_VALUE) int repeatCount,@Size(min = 0,max=Integer.MAX_VALUE) int duration, float. values){
                LogUtils.e("after");
                if(view==null) {throw new RuntimeException("View cannot be empty");
                }
                ObjectAnimator afterAnimator = ObjectAnimator.ofFloat(view,
                        animName, values).setDuration(duration);
                afterAnimator.setInterpolator(interpolator==null? mTimeInterpolator:interpolator); afterAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
                afterAnimator.setDuration(duration<0? mDuration:duration);if(afterListener! =null&&afterListener.animatorListener ! =null) {
                    afterAnimator.addListener(afterListener.animatorListener);
                }
                if(afterListener! =null&&afterListener.updateListener! =null){
                    afterAnimator.addUpdateListener(afterListener.updateListener);
                }
                if(afterListener! =null&&afterListener.pauseListener! =null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        afterAnimator.addPauseListener(afterListener.pauseListener);
                    }else{
                        throw new RuntimeException("SDK minimum requirement 19");
                    }
                }
                mAnimatorBuilder = mAnimatorBuilder.after(afterAnimator);
                return this;
            }
    
            public AnimatorSetWrap after(Animator animator) {
                mAnimatorBuilder = mAnimatorBuilder.after(animator);
                return this;
            }
    
            public AnimatorSetWrap after(AnimatorSetWrap animator) {
                mAnimatorBuilder = mAnimatorBuilder.after(animator.getAnimatorSet());
                return this;
            }
    
    
            public AnimatorSetWrap after(long delay) {
                mAnimatorBuilder.after(delay);
                return this;
            }
    
            /** * Executes the animation directly. This animation operation is mainly used to execute the composite animation of the AnimatorSet. * if the mAnimatorList is not 0, the animation is played one by one
            public void playAnim(a) {
                if(mAnimatorList.size()>0){
                    readyThen(true);
                }
                mAnimatorSet.start();
            }
    
            /** * Run the combination animation in a certain amount of time * if mAnimatorList is not 0 perform animation by animation *@paramDuration Animation duration */
            public void playAnim(long duration) {
                if(mAnimatorList.size()>0){
                    readyThen(true);
                }
                mAnimatorSet.setDuration(duration);
                mAnimatorSet.start();
            }
    
            /** * Delay playback of animation for a certain amount of time * if mAnimatorList is not 0 perform playback of animation one by one *@paramDelay Delay duration */
            public void playAnimDelay(long delay) {
                if(mAnimatorList.size()>0){
                    readyThen(true);
                }
                mAnimatorSet.setStartDelay(delay);
                mAnimatorSet.start();
            }
    
            /** * executes the animation directly. This animation operation is mainly used to execute the composite animation of the AnimatorSet */
            public void playAnim(boolean isSequentially) {
                readyThen(isSequentially);
                mAnimatorSet.start();
            }
    
            /** * Run the combined animation within a certain amount of time *@paramDuration Animation duration */
            public void playAnim(boolean isSequentially,long duration) {
                readyThen(isSequentially);
                mAnimatorSet.setDuration(duration);
                mAnimatorSet.start();
            }
    
            /** * Play the animation after a certain length of time@paramDelay Delay duration */
            public void playAnimDelay(boolean isSequentially,long delay) {
                readyThen(isSequentially);
                mAnimatorSet.setStartDelay(delay);
                mAnimatorSet.start();
            }
    
            /** * Play animations in sequence *@paramIsSequentially or simultaneously */
            private void readyThen(boolean isSequentially){
                // Initialize only on the first startup
                if (mHasInitThenAnim) {
                    return;
                }
                mHasInitThenAnim = true;
                if (mAnimatorList.size() > 0) {
                    AnimatorSet set = new AnimatorSet();
                    if(isSequentially){
                        set.playSequentially(mAnimatorList);
                    }else{ set.playTogether(mAnimatorList); } mAnimatorBuilder.before(set); }}/** * unanimate */
            public void cancel(a) {
                mAnimatorSet.cancel();
                mAnimatorList.clear();
            }
    
            /** * Get an instance of AnimatorSet *@return* /
            private AnimatorSet getAnimatorSet(a) {
                return mAnimatorSet;
            }
    
            /** * Set listener * for AnimatorSet@param listener
             * @return* /
            public AnimatorSetWrap setAnimatorSetListener(Animator.AnimatorListener listener) {
                mAnimatorSet.addListener(listener);
                return this;
            }
    
            /** * Unlisten AnimatorSet *@param listener
             */
            public void removeSetListner(Animator.AnimatorListener listener) {
                mAnimatorSet.removeListener(listener);
            }
    
            /** * Cancel all AnimatorSet listening */
            public void removeAllLSetisteners(a) {
                mAnimatorSet.removeAllListeners();
            }
    
            /** * Determine if a View is visible on the current screen *@param mView
             * @returnReturn true to see */
            public static boolean isVisibleOnScreen(View mView) {
                if (mView == null) {
                    return false;
                }
                returnmView.getWindowVisibility() == View.VISIBLE && mView.getVisibility() == View.VISIBLE && mView.isShown(); }}/** * Play method corresponding ObjectAnimator listening instance */
        public static class PlayAnimationListener implements IAnimatorListener<PlayAnimationListener>{
    
            private  Animator.AnimatorListener animatorListener;
            private ValueAnimator.AnimatorUpdateListener updateListener;
            private Animator.AnimatorPauseListener pauseListener;
    
            public AnimatorSetWrap animatorSetWrap;
            public  PlayAnimationListener(AnimatorSetWrap animatorSetWrap){
                    this.animatorSetWrap=animatorSetWrap;
            }
            @Override
            public PlayAnimationListener setAnimatorListener(Animator.AnimatorListener animatorListener) {
                this.animatorListener=animatorListener;
                return this;
            }
    
            @Override
            public PlayAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener animatorListener) {
                this.updateListener=animatorListener;
                return this;
            }
    
            @Override
            public PlayAnimationListener setPauseListener(Animator.AnimatorPauseListener animatorListener) {
                this.pauseListener=animatorListener;
                return this;
            }
            @Override
            public AnimatorSetWrap and(a){
                returnanimatorSetWrap; }}public static class BeforeAnimationListener implements IAnimatorListener<BeforeAnimationListener>{
    
            private  Animator.AnimatorListener animatorListener;
            private ValueAnimator.AnimatorUpdateListener updateListener;
            private Animator.AnimatorPauseListener pauseListener;
    
            public AnimatorSetWrap animatorSetWrap;
            public  BeforeAnimationListener(AnimatorSetWrap animatorSetWrap){
                this.animatorSetWrap=animatorSetWrap;
            }
            @Override
            public AnimatorSetWrap and(a) {
                return animatorSetWrap;
            }
    
            @Override
            public BeforeAnimationListener setAnimatorListener(Animator.AnimatorListener listener) {
                this.animatorListener=listener;
                return this;
            }
    
            @Override
            public BeforeAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
                this.updateListener=listener;
                return this;
            }
    
            @Override
            public BeforeAnimationListener setPauseListener(Animator.AnimatorPauseListener listener) {
                this.pauseListener=listener;
                return this; }}public static class WithAnimationListener implements IAnimatorListener<WithAnimationListener>{
    
            private  Animator.AnimatorListener animatorListener;
            private ValueAnimator.AnimatorUpdateListener updateListener;
            private Animator.AnimatorPauseListener pauseListener;
    
            public AnimatorSetWrap animatorSetWrap;
            public  WithAnimationListener(AnimatorSetWrap animatorSetWrap){
                this.animatorSetWrap=animatorSetWrap;
            }
            @Override
            public AnimatorSetWrap and(a) {
                return animatorSetWrap;
            }
    
            @Override
            public WithAnimationListener setAnimatorListener(Animator.AnimatorListener listener) {
                this.animatorListener=listener;
                return this;
            }
    
            @Override
            public WithAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
                this.updateListener=listener;
                return this;
            }
    
            @Override
            public WithAnimationListener setPauseListener(Animator.AnimatorPauseListener listener) {
                this.pauseListener=listener;
                return this; }}public static class AfterAnimationListener implements IAnimatorListener<AfterAnimationListener>{
    
            private  Animator.AnimatorListener animatorListener;
            private ValueAnimator.AnimatorUpdateListener updateListener;
            private Animator.AnimatorPauseListener pauseListener;
    
            public AnimatorSetWrap animatorSetWrap;
            public  AfterAnimationListener(AnimatorSetWrap animatorSetWrap){
                this.animatorSetWrap=animatorSetWrap;
            }
            @Override
            public AnimatorSetWrap and(a) {
                return animatorSetWrap;
            }
    
            @Override
            public AfterAnimationListener setAnimatorListener(Animator.AnimatorListener listener) {
                this.animatorListener=listener;
                return this;
            }
    
            @Override
            public AfterAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
                this.updateListener=listener;
                return this;
            }
    
            @Override
            public AfterAnimationListener setPauseListener(Animator.AnimatorPauseListener listener) {
                this.pauseListener=listener;
                return this; }}public static class ThenAnimationListener implements IAnimatorListener<ThenAnimationListener>{
    
            private  Animator.AnimatorListener animatorListener;
            private ValueAnimator.AnimatorUpdateListener updateListener;
            private Animator.AnimatorPauseListener pauseListener;
    
            public AnimatorSetWrap animatorSetWrap;
            public  ThenAnimationListener(AnimatorSetWrap animatorSetWrap){
                this.animatorSetWrap=animatorSetWrap;
            }
            @Override
            public AnimatorSetWrap and(a) {
                return animatorSetWrap;
            }
    
            @Override
            public ThenAnimationListener setAnimatorListener(Animator.AnimatorListener listener) {
                this.animatorListener=listener;
                return this;
            }
    
            @Override
            public ThenAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
                this.updateListener=listener;
                return this;
            }
    
            @Override
            public ThenAnimationListener setPauseListener(Animator.AnimatorPauseListener listener) {
                this.pauseListener=listener;
                return this; }}/** * Public template interface * for animation listening@param <T>
         */
        interface IAnimatorListener<T>{
            /** * Set the AnimatorListener method *@param listener
             * @return* /
            T setAnimatorListener(Animator.AnimatorListener listener);
    
            /** * The AnimatorUpdateListener method *@param listener
             * @return* /
            T setUpdateListener(ValueAnimator.AnimatorUpdateListener listener);
    
            /** * The AnimatorPauseListener method *@param listener
             * @return* /
            T setPauseListener(Animator.AnimatorPauseListener listener);
    
            /** * Bridge the animation listener to the animation tool class@return* /
            AnimatorSetWrap and(a); }}Copy the code

    Usage:

    AnimatorUtils.createAnimator().play(viewAnimator,AnimatorUtils.ROTATIONY,null.0.1000.0.360).toAddThenListener().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    LogUtils.e("then1:"+valueAnimator.getAnimatedValue());
                }
            }).and().then(viewAnimator, AnimatorUtils.TRANSY, null, -1, -2.0.100.200.300.200.100.0).toAddThenListener().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    LogUtils.e("then2:"+valueAnimator.getAnimatedValue());
                }
            }).and().then(viewAnimator, AnimatorUtils.SCALEX, new LinearInterpolator(), 0.1000.0.10).toAddWithListener().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    LogUtils.e("with1:"+valueAnimator.getAnimatedValue());
                }
            }).and().with(viewAnimator, AnimatorUtils.SCALEY, new LinearInterpolator(), 0.1000.0.10).toAddWithListener().setAnimatorListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animator) {
                    LogUtils.e("with2:onAnimationStart");
                }
    
                @Override
                public void onAnimationEnd(Animator animator) {}@Override
                public void onAnimationCancel(Animator animator) {}@Override
                public void onAnimationRepeat(Animator animator) {
    
                }
            }).and().with(viewAnimator, AnimatorUtils.ALPHA, new LinearInterpolator(), 0.1000.1.0.1)
            //.playSequentially(2000);
            .playAnim();
    Copy the code

    The above animation call method is I scrawled, specific is to demonstrate the use of tool class method, you can change your call method.