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
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:
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>
Get the animation in java code
animationDrawable = (AnimationDrawable) img.getBackground();
Use this animation
animationDrawable.start(); //开启动画
animationDrawable.stop(); //停止动画
2. java code method
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);
- 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 label2.xml code and attribute description: (Create anim directory under res, new xml file in anim)
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,完全透明-完全不透明
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%就是以图像的 中心为中轴点
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坐标
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,表示偶数次显示动画时会做方向相反的运动!
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
RotateAnimation
RotateAnimation rotateAnimation = new RotateAnimation(0, 360); rotateAnimation.setRepeatCount(1); rotateAnimation.setRepeatMode(Animation.REVERSE); rotateAnimation.setDuration(2000); mImageView.startAnimation(rotateAnimation);
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);
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 bytranslationX()
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
View
actual operation methods corresponding to the methods are shown in the figure below:As can be seen from the figure,
View
each method of corresponds toViewPropertyAnimator
two methods of , one of which has-By
the suffix, for example,View.setTranslationX()
corresponds to the two methodsViewPropertyAnimator.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 increasedtranslationX(100)
by animation , and means that the value of is gradually increased by animation .View
translationX
100
translationXBy(100)
View
translationX
100
Image understanding: If
-By
this 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-By
this 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
- If it is a custom control, you need to add the
setter
/getter
method;- Use to
ObjectAnimator.ofXXX()
createObjectAnimator
an object; (must have corresponding setter and getter methods)- 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
: callsetInterpolator(Interpolator interpolator)
setupThe system provides nine default differentiators as follows:
AccelerateDecelerateInterpolator: This is the default
Interpolator
3. Set up the listener:
The method of setting a listener is slightly different
ViewPropertyAnimator
from 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.ObjectAnimator
ViewPropertyAnimator
setListener()
setUpdateListener()
setUpdate]Listener(null)
ObjectAnimator
addListener()
addUpdateListener()
removeUpdateListener()
In addition, since
ObjectAnimator
it supports pausing usingpause()
the method, it also has an additionaladdPauseListener()
/removePauseListener()
support; andViewPropertyAnimator
has a uniquewithStartAction(Runnable)
andwithEndAction(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.AnimatorListener
There 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 setAnimatorListener
,onAnimationCancel()
both andonAnimationEnd()
will be called. will be calledonAnimationCancel()
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
ViewPropertyAnimator
does not support duplication, this method isViewPropertyAnimator
equivalent 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
,ValueAnimator
which isObjectAnimator
the parent class of andViewPropertyAnimator
the internal implementation of , so this parameter is actuallyViewPropertyAnimator
the one insideValueAnimator
(inconsistent with the ViewPropertyAnimator instance), orObjectAnimator
it 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
ViewPropertyAnimator
unique to . There are two main differences between them and the /set/addListener()
in the callback :onAnimationStart()
onAnimationEnd()
withStartAction(Runnable)
/withEndAction(Runnable)
is a one-time use and is automatically discarded after the animation is executed. Even if it is reusedViewPropertyAnimator
for other animations later, the callbacks set with them will not be called again. Theset/addListener()
settingAnimatorListener
is continuously valid. When the animation is executed repeatedly, the callback will always be called.withEndAction(Runnable)
The set callback will only be called when the animation ends normally, and will not be executed when the animation is cancelled. ThisAnimatorListener.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:
<?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.
PropertyValuesHolder
It is not possible to use in this case , because if these attributes are placed in the same animation, they need to shareInterpolator
a 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 toofFloat()
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 useTypeEvaluator
it . For example, changing the color, etc.Usage: With the help of
TypeEvaluator
attribute animation, you canofObject()
animate attributes of unlimited types through . The method is very simple:
- Write a custom one for the target attribute
TypeEvaluator
- Use
ofObject()
to createAnimator
and fill in the customTypeEvaluator
ones as parametersValueAnimator 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:
- 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
- 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.
- 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.)