About the use and summary of Android frame animation, tweening animation, and attribute animation. (Source code attached)

Note: There is a lot of content, so you can read it in chunks. It may be divided into three lectures later.

1. Android animation summary

1. Frame animation

Frame animation actually simulates animation effects by continuously playing pictures.

The following are two ways to achieve it:

1. xml file method

  1. First create animation_lufi.xml under drawable

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="false">
        <item android:drawable="@drawable/image7"
            android:duration="200"/>
        <item android:drawable="@drawable/image8"
            android:duration="200"/>
        <item android:drawable="@drawable/image9"
            android:duration="200"/>
        <item android:drawable="@drawable/image10"
            android:duration="200"/>
    
    </animation-list>
    

    You can preview the effect:

Insert image description here

  1. Add animation_lufi.xml as the background in the view in the layout file

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
        <View
            android:id="@+id/image"
            android:layout_width="300dp"
            android:layout_height="300dp"
            android:background="@drawable/animation_lufi"    
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/end" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    
  2. Get the animation in java code

    animationDrawable = (AnimationDrawable) img.getBackground();
    
  3. Use this animation

    animationDrawable.start(); //开启动画
    
    animationDrawable.stop(); //停止动画
    

2. java code method

  1. In java code:

            animationDrawable = new AnimationDrawable();
            animationDrawable.addFrame(getResources().getDrawable(R.drawable.image7),250);
            animationDrawable.addFrame(getResources().getDrawable(R.drawable.image8),250);
            animationDrawable.addFrame(getResources().getDrawable(R.drawable.image9),250);
            animationDrawable.addFrame(getResources().getDrawable(R.drawable.image10),250);
            img.setBackground(animationDrawable);
    
    1. Other uses remain unchanged. It's just that the way to get the instance is different from the way to add the frame.

2. Tween animation

Tween animation developers only need to specify the animation start and animation end "key frames", and the "intermediate frames" of animation changes are calculated and completed by the system.

1. Types of tween animations

AlphaAnimation:: Transparency gradient effect, specify the start and end transparency when creating, as well as the duration of the animation, the change range of transparency (0,1), 0 is completely transparent, 1 is completely opaque; corresponding label <alpha/>!
ScaleAnimation: Scale gradient effect. When creating, you need to specify the start and end scaling ratios, as well as the scaling reference point, and the duration of the animation; corresponding <scale/>label!
TranslateAnimation: Displacement gradient effect, specify the starting and ending positions when creating, and specify the duration of the animation; corresponding <translate/>label!
RotateAnimation: Rotation gradient effect. When creating, specify the starting and ending rotation angles of the animation, as well as the animation duration and the axis of rotation; corresponding <rotate/>tags
AnimationSet: Combined gradient is a combination of the previous gradients, corresponding to <set/>the label

2.xml code and attribute description: (Create anim directory under res, new xml file in anim)

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-4q5lhTok-1686710312405) (C:\Users\SW\AppData\Roaming\Typora\typora-user-images\ image-20230526154902325.png)]

Insert image description here

Insert image description here

  1. AlphaAnimation:: anim_alpha.xml

    <?xml version="1.0" encoding="utf-8"?>
    <alpha xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromAlpha="1.0"
        android:toAlpha="0.1"
        android:duration = "3000"
        />
    
    fromAlpha : 起始透明度
    toAlpha : 结束透明度
    透明度的范围为:0-1,完全透明-完全不透明
    
  2. ScaleAnimation:anim_scale.xml

    <?xml version="1.0" encoding="utf-8"?>
    <scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:fromXScale="0.2"
        android:toXScale="1.5"
        android:fromYScale="0.2"
        android:toYScale="1.5"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="2000"/>
    
    fromXScale/fromYScale:沿着X轴/Y轴缩放的起始比例
    toXScale/toYScale:沿着X轴/Y轴缩放的结束比例
    pivotX/pivotY:缩放的中轴点X/Y坐标,即距离自身左边缘的位置,比如50%就是以图像的 中心为中轴点
    
  3. TranslateAnimation: anim_translate.xml

    <?xml version="1.0" encoding="utf-8"?>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromXDelta="0"
        android:toXDelta="320"
        android:fromYDelta="0"
        android:toYDelta="-320"
        android:duration="2000"/>
    
    fromXDelta/fromYDelta:动画起始位置的X/Y坐标
    toXDelta/toYDelta:动画结束位置的X/Y坐标
    
  4. RotateAnimation:anim_rotate.xml

    <?xml version="1.0" encoding="utf-8"?>
    <rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromDegrees="0"
        android:toDegrees="129"
        android:duration="1000"
        android:repeatCount="1"
        android:repeatMode="reverse"/>
    
    fromDegrees/toDegrees:旋转的起始/结束角度
    
    repeatCount:旋转的次数,默认值为0,代表一次,假如是其他值,比如3,则旋转4次 另外,值为-1或者infinite时,表示动画永不停止
    
    repeatMode:设置重复模式,默认restart,但只有当repeatCount大于0或者infinite或-1时 才有效。还可以设置成reverse,表示偶数次显示动画时会做方向相反的运动!
    
    
  5. AnimationSet: In fact, it is a collection of several animations (and several animations start playing at the same time)

    anim_set.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:shareInterpolator="true" >
        <scale
            android:duration="2000"
            android:fromXScale="0.2"
            android:fromYScale="0.2"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toXScale="1.5"
            android:toYScale="1.5" />
        <rotate
            android:duration="1000"
            android:fromDegrees="0"
            android:repeatCount="1"
            android:repeatMode="reverse"
            android:toDegrees="360" />
        <translate
            android:duration="2000"
            android:fromXDelta="0"
            android:fromYDelta="0"
            android:toXDelta="320"
            android:toYDelta="0" />
        <alpha
            android:duration="2000"
            android:fromAlpha="1.0"
            android:toAlpha="0.1" />
    </set>
    
    android:shareInterpolator="true" : 为true时,set中的所有动画都共享同一插值器。 为false时,需要为set中每个动画都设置单独的插值器  (Interpolator)
    

3. The java code loads the xml animation to obtain the animation instance and start it.

                //利用AnimationUtils从xml中加载获取Animation实例
               Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.anim_alpha); 
               //调用view去开启动画 
               mImageView.startAnimation(animation);

The above is the java code for loading anim_alpha.xml animation. Same for other things

4. Directly create animation instances in java

  1. RotateAnimation

                    RotateAnimation rotateAnimation = new RotateAnimation(0, 360);
                    rotateAnimation.setRepeatCount(1);
                    rotateAnimation.setRepeatMode(Animation.REVERSE);
                    rotateAnimation.setDuration(2000);
                    mImageView.startAnimation(rotateAnimation);
    
  2. AnimationSet

                    Animation rotateAnimation = new RotateAnimation(0, -720, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                            RotateAnimation.RELATIVE_TO_SELF, 0.5f);
                    rotateAnimation.setDuration(2000);
                    Animation translateAnimation = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT, 0, TranslateAnimation.RELATIVE_TO_PARENT, 0.5f,
                            TranslateAnimation.RELATIVE_TO_PARENT, 0, TranslateAnimation.RELATIVE_TO_PARENT, 0.5f);
                    translateAnimation.setDuration(2000);
                    Animation scaleAnimation = new ScaleAnimation(0, 1.4f, 0, 1.4f, ScaleAnimation.RELATIVE_TO_SELF,
                            0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
                    scaleAnimation.setDuration(2000);
                    Animation alphaAnimation = new AlphaAnimation(0, 1);
                    alphaAnimation.setDuration(2000);
                    AnimationSet animationSet = new AnimationSet(true);
                    animationSet.addAnimation(rotateAnimation);
                    animationSet.addAnimation(translateAnimation);
                    animationSet.addAnimation(scaleAnimation);
                    animationSet.addAnimation(alphaAnimation);
                    animationSet.setDuration(4000);
                    animationSet.setFillAfter(false);
                    mImageView.startAnimation(animationSet);
    
  3. The same applies to other animations

5. Tween animation monitoring

Call setAnimationListener(AnimationListener listener) of the animation object to set the listener
           scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
     
     
                    @Override
                    public void onAnimationStart(Animation animation) {
     
     
                        Log.d(TAG, "onAnimationStart:  开始" );
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
     
     
                        Log.d(TAG, "onAnimationEnd:  结束");
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {
     
     
                        Log.d(TAG, "onAnimationRepeat: 重复");
                    }
                });

​onAnimationStart (): Called when the animation starts

​onAnimtaionRepeat (): Called when the animation is played repeatedly

​onAnimationEnd (): Called when the animation ends

If it is an animation that is repeated twice, then onAnimtaionRepeat will be called twice, but start and end will only be called once.

3. Attribute animation

1. ViewPropertyAnimator

1. Use

It is relatively simple to use: View.animate()followed by translationX()other methods, the animation will be executed automatically. For example:

            imageView.animate().translationYBy(-100).translationXBy(100).setDuration(3000)
                     .setInterpolator(new AccelerateDecelerateInterpolator()).start();

The specific methods that can be followed and the Viewactual operation methods corresponding to the methods are shown in the figure below:

Insert image description here

As can be seen from the figure, Vieweach method of corresponds to ViewPropertyAnimatortwo methods of , one of which has -Bythe suffix, for example, View.setTranslationX()corresponds to the two methods ViewPropertyAnimator.translationX()of and . ViewPropertyAnimator.translationXBy()The method with -By()the suffix is ​​the incremental version of the method. For example, it means that the value of is gradually increased translationX(100)by animation , and means that the value of is gradually increased by animation .ViewtranslationX100translationXBy(100)ViewtranslationX100

Image understanding: If -Bythis method is not used, after clicking once to play the animation, when the animation ends (that is, when the changed value has reached the end value), the animation will not play when you click again to play the animation (because the end value has been reached) , will not change again). However, if you use -Bythis method, the animation will still play if you click again, because every time you click, the properties of the corresponding method will increase and it will "move"

for example:

imageView.animate().translationYBy(-100).translationX(100).start();

When clicked for the first time, both x and y will move. After that, only y will move every time you click. Because X has reached the end value after the first playback, and Y is -100 every time;

2. Monitoring

setListener(new Animator.AnimatorListener() {
     
     
                     @Override
                     public void onAnimationStart(@NonNull Animator animation) {
     
     
                             Log.d(TAG, "onAnimationStart: 开始");
                     }

                     @Override
                     public void onAnimationEnd(@NonNull Animator animation) {
     
     
                             Log.d(TAG, "onAnimationEnd:   结束");
                     }

                     @Override
                     public void onAnimationCancel(@NonNull Animator animation) {
     
     
                             Log.d(TAG, "onAnimationCancel:  取消");
                     }

                     @Override
                     public void onAnimationRepeat(@NonNull Animator animation) {
     
     
                              Log.d(TAG, "onAnimationRepeat:  重复");
                         }
                     })

The above methods are summarized later

2.ObjectAnimator

Usage: java code

  1. If it is a custom control, you need to add the setter/ gettermethod;
  2. Use to ObjectAnimator.ofXXX()create ObjectAnimatoran object; (must have corresponding setter and getter methods)
  3. Use start()the method to perform animations.
                animator =ObjectAnimator.ofFloat(imageView,"alpha",1f,0f,1f);
                animator.setDuration(5000); //过渡时间
                //动画延迟500ms执行
                animator.setStartDelay(500);
                //执行重复次数 +1
                animator.setRepeatCount(1);
                // 设置动画重复播放模式 RESTART -执行完一遍后重新执行
                // REVERSE -执行完一遍后 从末位置往前执行
                animator.setRepeatMode(ValueAnimator.REVERSE);
                animator.start();

Interpolator Interpolator: call setInterpolator(Interpolator interpolator)setup

The system provides nine default differentiators as follows:

Insert image description here

AccelerateDecelerateInterpolator: This is the defaultInterpolator

3. Set up the listener:

The method of setting a listener is slightly different ViewPropertyAnimatorfrom that of : using the and method, you can set a listener, and when you want to remove the listener, fill in the null value to remove it; and use and to add one or more listeners , to remove the listener, specify the object to be removed.ObjectAnimatorViewPropertyAnimatorsetListener()setUpdateListener()setUpdate]Listener(null)ObjectAnimatoraddListener()addUpdateListener()removeUpdateListener()

In addition, since ObjectAnimatorit supports pausing using pause()the method, it also has an additional addPauseListener()/ removePauseListener()support; and ViewPropertyAnimatorhas a unique withStartAction(Runnable)and withEndAction(Runnable)method, which can set up a one-time monitoring of the start or end of the animation.

3.1 ViewPropertyAnimator.setListener() / ObjectAnimator.addListener()

The names of these two methods are different, and the number of listeners that can be set is also different, but their parameter types are the same AnimatorListener, so they are essentially the same. AnimatorListenerThere are 4 callback methods:

3.1.1 onAnimationStart(Animator animation)

This method is called when the animation starts executing.

3.1.2 onAnimationEnd(Animator animation)

This method is called when the animation ends.

3.1.3 onAnimationCancel(Animator animation)

cancel()This method is called when the animation is canceled via the method.

It should be noted that even if the animation is canceled, onAnimationEnd()it will still be called. So when the animation is cancelled, if set AnimatorListener, onAnimationCancel()both and onAnimationEnd()will be called. will be called onAnimationCancel()before .onAnimationEnd()

3.1.4 onAnimationRepeat(Animator animation)

This method is called when the animation is repeated via setRepeatMode()the / setRepeatCount()or method.repeat()

Since ViewPropertyAnimatordoes not support duplication, this method is ViewPropertyAnimatorequivalent to invalid.

                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
     
     
                    @Override
                    public void onAnimationUpdate(@NonNull ValueAnimator animation) {
     
     
                        Log.d(TAG, "onAnimationUpdate: " + animation.getAnimatedValue());
                    }
                });
                animator.addPauseListener(new Animator.AnimatorPauseListener() {
     
     
                    @Override
                    public void onAnimationPause(@NonNull Animator animation) {
     
     
                        Log.d(TAG, "onAnimationPause: ");
                    }

                    @Override
                    public void onAnimationResume(@NonNull Animator animation) {
     
     
                        Log.d(TAG, "onAnimationResume: ");
                    }
                });
                animator.addListener(new Animator.AnimatorListener() {
     
     
                    @Override
                    public void onAnimationStart(@NonNull Animator animation) {
     
     
                        Log.d(TAG, "onAnimationStart: ");
                    }

                    @Override
                    public void onAnimationEnd(@NonNull Animator animation) {
     
     
                        Log.d(TAG, "onAnimationEnd: ");
                    }

                    @Override
                    public void onAnimationCancel(@NonNull Animator animation) {
     
     
                        Log.d(TAG, "onAnimationCancel: ");
                    }

                    @Override
                    public void onAnimationRepeat(@NonNull Animator animation) {
     
     
                        Log.d(TAG, "onAnimationRepeat: ");
                    }
                });

3.2 ViewPropertyAnimator.setUpdateListener() / ObjectAnimator.addUpdateListener()

Like the two methods in 3.1 above, although these two methods have different names and the number of settable listeners, their essence is actually the same, and their parameters are the same AnimatorUpdateListener. It has only one callback method: onAnimationUpdate(ValueAnimator animation).

3.2.1 onAnimationUpdate(ValueAnimator animation)

This method is called when the animated properties are updated.

The parameter of the method is one ValueAnimator, ValueAnimatorwhich is ObjectAnimatorthe parent class of and ViewPropertyAnimatorthe internal implementation of , so this parameter is actually ViewPropertyAnimatorthe one inside ValueAnimator(inconsistent with the ViewPropertyAnimator instance), or ObjectAnimatorit is itself for (that is to say, the parameter instance of the listening method is the same as the calling Its instances are the same).

3.3 ObjectAnimator.addPauseListener()

3.4 ViewPropertyAnimator.withStartAction/EndAction(Runnable)

These two methods are ViewPropertyAnimatorunique to . There are two main differences between them and the / set/addListener()in the callback :onAnimationStart()onAnimationEnd()

  1. withStartAction(Runnable)/ withEndAction(Runnable)is a one-time use and is automatically discarded after the animation is executed. Even if it is reused ViewPropertyAnimatorfor other animations later, the callbacks set with them will not be called again. The set/addListener()setting AnimatorListeneris continuously valid. When the animation is executed repeatedly, the callback will always be called.
  2. withEndAction(Runnable)The set callback will only be called when the animation ends normally, and will not be executed when the animation is cancelled. This AnimatorListener.onAnimationEnd()is inconsistent with the behavior of .

4. Obtain ObjectAnimator through xml method

You need to create an animator under res, and then create an xml file under the animator:

Insert image description here

Insert image description here

Insert image description here

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="alpha"
    android:valueFrom="1"
    android:valueTo="0"
    android:valueType="floatType" />

java code acquisition:

               animator = (ObjectAnimator) AnimatorInflater.loadAnimator(MainActivity.this,R.animator.animator_alpha); //xml方式 <ObjectAnimator>标签代码 objectAnimator
               animator.setTarget(imageView); //xml方式,需要加个Target

Review: tweened animations are loaded using AnimationUtils.loadAnimation

Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.anim_alpha);

3.ValueAnimator

ValueAnimator (value animation) realizes animation by controlling the change of value and then manually assigning it to the properties of the object.

The core methods of ValueAnimator's java code are as follows:

ValueAnimator ofFloat(float... values) // 浮点型数值
ValueAnimator  ofInt(int... values) // 整型数值
ValueAnimator  ofObject(TypeEvaluator evaluator, Object... values) // 自定义对象类型

Use java code to get ValueAnimator:

             anim = ValueAnimator.ofFloat(0f, 1f); 
             anim.setDuration(5000);
             anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
     
     
                 @Override
                 public void onAnimationUpdate(ValueAnimator animation) {
     
     
                     float currentValue = (float) animation.getAnimatedValue();
                     Log.d("MainActivity", "cuurent value is " + currentValue);
                     imageView.setAlpha(currentValue);
                 }
             });
             anim.start();

Use xml to get ValueAnimator:

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
 android:valueFrom="0f"
 android:valueTo="1f"
 android:valueType="floatType"
 />

2. Get the ValueAnimator instance in java code:

anim =(ValueAnimator) AnimatorInflater.loadAnimator(this,R.animator.animator_value); //xml方式 <animator>标签代表 ValueAnimator

4.PropertyValuesHolder

PropertyValuesHolder Changing multiple properties in the same animation can also be understood as starting multiple animations at the same time.

use:

              PropertyValuesHolder alphaProper =  PropertyValuesHolder.ofFloat("alpha", 0.5f, 1f);
              PropertyValuesHolder scaleXProper = PropertyValuesHolder.ofFloat("scaleX", 0f, 1f);
              PropertyValuesHolder scaleYProper = PropertyValuesHolder.ofFloat("scaleY", 0f, 1f);
              PropertyValuesHolder translationXProper = PropertyValuesHolder.ofFloat("translationX", -100, 0);
              PropertyValuesHolder translationYProper = PropertyValuesHolder.ofFloat("translationY", -100, 0);
              PropertyValuesHolder rotationProper = PropertyValuesHolder.ofFloat("rotation", 0, 360);
              ValueAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageView, alphaProper,
                      scaleXProper, scaleYProper,translationXProper,translationYProper,rotationProper);
              animator.setDuration(5000);
              animator.setRepeatCount(2);
              animator.setRepeatMode(ValueAnimator.REVERSE);
              animator.start();
public static ObjectAnimator ofPropertyValuesHolder(Object target,    PropertyValuesHolder... values)  //方法
Advanced use: PropertyValuesHolders.ofKeyframe() splits the same property
             Keyframe keyframe1 = Keyframe.ofFloat(0f, 0);    //动画完成0,到达0
             Keyframe keyframe2 = Keyframe.ofFloat(1f, 100);  //动画完成100%到达100
             Keyframe keyframe = Keyframe.ofFloat(0.5f, 200); //动画完成50%到达200
             PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX", keyframe1, keyframe, keyframe2);
             ObjectAnimator animator2 = ObjectAnimator.ofPropertyValuesHolder(imageView, holder);
             animator2.setDuration(2000);
             animator2.start();

5.AnimatorSet

AnimatorSet Multiple animations are executed together

Sometimes, you not only need to change multiple properties in one animation, but also need multiple animations to work together. For example, when the size of the content is enlarged from 0 to 100%, it starts to move. PropertyValuesHolderIt is not possible to use in this case , because if these attributes are placed in the same animation, they need to share Interpolatora series of settings such as the animation's start time, end time, etc., so that the animation cannot be executed sequentially.

So AnimatorSet is needed

               ObjectAnimator rotate = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f);
               ObjectAnimator translationX = ObjectAnimator.ofFloat(imageView, "translationX", -100, 0);
               ObjectAnimator translationY = ObjectAnimator.ofFloat(imageView, "translationY", 0, -100);
               ObjectAnimator scaleX = ObjectAnimator.ofFloat(imageView, "scaleX", 0, 1f);
               ObjectAnimator scaleY = ObjectAnimator.ofFloat(imageView, "scaleY", 1, 0.5f);
               ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView, "alpha", 1f, 0f, 1f);
               animSet = new AnimatorSet();
               animSet.play(rotate)
                       .with(alpha)
                       .before(scaleX)
                       .after(scaleY)
                       .with(translationX)
                       .before(translationY);
               animSet.setDuration(2000);
               animSet.start();
Note: The same level will be played together at the same time. For example, if two withs are set, no matter where they are placed, they will play at the same time as the animation passed in by play, similar to after and before.

6.TypeEvaluator evaluator

Regarding ObjectAnimator, it can be used ofInt()to animate the properties of integers and to ofFloat()animate decimal properties. These two attribute types are the two most commonly used for attribute animation. However, in actual development, there are other types that can be used for attribute animation. When you need to animate properties of other types, you need to use TypeEvaluatorit . For example, changing the color, etc.

Usage: With the help of TypeEvaluatorattribute animation, you can ofObject()animate attributes of unlimited types through . The method is very simple:

  1. Write a custom one for the target attributeTypeEvaluator
  2. Use ofObject()to create Animatorand fill in the custom TypeEvaluatorones as parameters
ValueAnimator  ofObject(TypeEvaluator evaluator, Object... values)
ObjectAnimator ofObject(Object target, String propertyName,TypeEvaluator evaluator, Object... values)

From the source code of the TypeEvaluator evaluator, we can see that the function of this class is to tell the animation how to transition from the starting value to the ending value.
There are several classes in the Android source code that implement this interface, which are some default evaluators provided by the system. Let's take FloatEvaluator as an example to look at its implementation code.

public class FloatEvaluator implements TypeEvaluator<Number> {
     
     
    public Float evaluate(float fraction, Number startValue, Number endValue) {
     
     
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}

From the implementation of FloatEvaluator, we can see that in the evaluate method, the end value is subtracted from the initial value, the difference between them is calculated, and then multiplied by the coefficient of fraction, plus the initial value, then the value of the current animation is obtained.

PS: Fraction is the degree of completion, it will continuously change from 0 to 1

Custom TypeEvaluator: Just implement TypeEvaluator and write a custom algorithm.

For example: write an estimator that changes color

public class MyTypeEvaluator implements TypeEvaluator<String> {
     
     
    private int mCurrentRed = -1;
    private int mCurrentGreen = -1;
    private int mCurrentBlue = -1;
    @Override
    public String evaluate(float fraction, String startValue, String endValue) {
     
     
        Log.d("text", "evaluate: " + fraction);
        int startRed = Integer.parseInt(startValue.substring(1, 3), 16);
        int startGreen = Integer.parseInt(startValue.substring(3, 5), 16);
        int startBlue = Integer.parseInt(startValue.substring(5, 7), 16);
        int endRed = Integer.parseInt(endValue.substring(1, 3), 16);
        int endGreen = Integer.parseInt(endValue.substring(3, 5), 16);
        int endBlue = Integer.parseInt(endValue.substring(5, 7), 16);
        Log.d("TAG", "evaluate: " + startRed + "   " + startGreen + "    " + startBlue + "    "
         + endRed + "    " + endGreen + "   " +endBlue);
        // 初始化颜色的值
        if (mCurrentRed == -1) {
     
     
            mCurrentRed = startRed;
        }
        if (mCurrentGreen == -1) {
     
     
            mCurrentGreen = startGreen;
        }
        if (mCurrentBlue == -1) {
     
     
            mCurrentBlue = startBlue;
        }
        // 计算初始颜色和结束颜色之间的差值
        int redDiff = Math.abs(startRed - endRed);
        int greenDiff = Math.abs(startGreen - endGreen);
        int blueDiff = Math.abs(startBlue - endBlue);

        if (mCurrentRed != endRed) {
     
     
            mCurrentRed = getCurrentColor(startRed, endRed, redDiff, fraction);

        }
        if (mCurrentGreen != endGreen) {
     
     
            mCurrentGreen = getCurrentColor(startGreen, endGreen, greenDiff, fraction);

        }
        if (mCurrentBlue != endBlue) {
     
     
            mCurrentBlue = getCurrentColor(startBlue, endBlue,blueDiff, fraction);


        }
        Log.d("test", "evaluate: " + mCurrentRed + "    " + mCurrentGreen + "   "+mCurrentBlue);
        // 将计算出的当前颜色的值组装返回
        String currentColor = "#" + getHexString(mCurrentRed)
                + getHexString(mCurrentGreen) + getHexString(mCurrentBlue);
        return currentColor;
    }
    /**
     * 根据fraction值来计算当前的颜色。
     */
    private int getCurrentColor(int startColor, int endColor, int colorDiff, float fraction) {
     
     
        int currentColor;
        if (startColor > endColor) {
     
     
            currentColor = (int) (startColor - (fraction * colorDiff));
            if (currentColor <= endColor) {
     
     
                currentColor = endColor;
            }
        } else {
     
     
            currentColor = (int) (startColor + (fraction * colorDiff));
            if (currentColor >= endColor) {
     
     
                currentColor = endColor;
            }
        }
        return currentColor;
    }
    /**
     * 将10进制颜色值转换成16进制。
     */
    private String getHexString(int value) {
     
     
        String hexString = Integer.toHexString(value);
        if (hexString.length() == 1) {
     
     
            hexString = "0" + hexString;
        }
        return hexString;
    }
}

use:

 ValueAnimator animator1 = ValueAnimator.ofObject( new MyTypeEvaluator(), "#123456", "#ABCDEF");
 animator1.setDuration(3000);
 animator1.start();

Property animation demo video: not public

Summary of the differences between tween animation and attribute animation:

  1. Limitation of objects: View tweening animation can only be used on the view, that is, it can only animate a Button, TextView, or even a LinearLayout, or other components inherited from the View, but it cannot animate non-View objects. . In some cases, the animation effect is only a certain attribute & object of the view rather than the entire view; for example, if you need to dynamically change the color of the view, you need to operate the color attribute of the view to achieve the animation effect, rather than animating the entire view. operate
  2. It does not change the properties of the View but only changes the visual effects: Tweening animation only changes the visual effects of the View without actually changing the properties of the View. For example, moving the button in the upper left corner of the screen to the lower right corner of the screen through tweening animation has no effect. Clicking the current button position (lower right corner of the screen) has no effect, because the button actually stays in the upper left corner of the screen, and the tweening animation just moves the button Drawing it to the lower right corner of the screen just changes the visual effect.
  3. Single animation effect: Tween animation can only achieve simple animation requirements such as translation, rotation, scaling & transparency. Property animation can use estimators to use custom algorithms to change other properties (such as color, etc.)

Project address: not public

Guess you like

Origin blog.csdn.net/XJ200012/article/details/131198776