After the study in the previous chapter, we have learned the basic use of attribute animation. In this chapter, we will talk about the underlying implementation of attribute animation, briefly talk about what is TimeInterpolator, what is TypeEvaluator, and how they work to present the animation we see.
Animator execution process
Let's demonstrate the execution process during animation from a simple example:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
animator = ValueAnimator.ofFloat(0,800);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
ivContainer.setTranslationY((Float) animation.getAnimatedValue());
}
});
rgInterpolatorType.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
ivContainer.setTranslationY(0);
}
});
}
protected void valueAnalysis(View view) {
log = new StringBuilder("");
switch (rgInterpolatorType.getCheckedRadioButtonId()) {
case R.id.rb_type_linear:
animator.setInterpolator(new LinearInterpolator());//线性插值器
break;
case R.id.rb_type_accelerate_decelerate:
animator.setInterpolator(new AccelerateDecelerateInterpolator());//先加速后减速
break;
case R.id.rb_type_bounce:
animator.setInterpolator(new BounceInterpolator());//弹跳
break;
}
animator.start();
}
The program execution effect is as follows:
It can be seen that after using three different Interpolators, the animation execution effect is different. LinearInterpolator is executed at a uniform speed, and the change value in each time segment is the same. AccelerateDecelerateInterpolator is to accelerate and then decelerate, and the last one has a rebound The effect, why is this happening, we click on LinearInterpolator and AccelerateDecelerateInterpolator, we can see that there are two interesting methods:
public float getInterpolation(float input) {
//LinearInterpolator
return input;
}
public float getInterpolation(float input) {
//AccelerateDecelerateInterpolator
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
We have directly concluded here. This method receives a time factor (current animation execution time/animation duration) in the use of attribute animation, and then returns a float value (0~1), which represents the animation from start to end, and then returns The value will be passed into the TypeEvaluator evaluate(float fraction, Object startValue, Object endValue)
method as the first parameter, and then the current value (endValue - startValue)*fraction+startValue will be calculated based on the start value and end value. In this way, it is not difficult to understand the principle of AccelerateDecelerateInterpolator to accelerate first and then decelerate. You can clearly know the trend of the cosine curve π~2π. BounceInterpolator, because of my limited mathematical level, will not be ugly. If you are interested, you can open the source code to view the implementation principle.
So far, we have understood how the execution flow of an animation is. When the animation starts to execute, it will dynamically calculate the time factor timeFraction (current animation execution time/animation duration), and then use the getInterpolation method of TimeInterpolator to get a suitable interpolation factor fraction, and then TypeEvaluator uses this interpolation factor to calculate the current value (float). , int, argb, object, etc.), and then call the onAnimationUpdate method of AnimatorUpdateListener to get the current value. The ObjectAnimator uses reflection to automatically set a property value named propertyName for the taeget we pass in (using setter and getter methods).
Finally, list some methods defined in Animator, or check the official documentation
Public methods | |
---|---|
void |
addListener(Animator.AnimatorListener listener) Add animation listener |
void |
addPauseListener(Animator.AnimatorPauseListener listener) Add animation pause listener |
void |
cancel() Cancel animation |
Animator |
clone() Returns a copy of the current animation |
void |
end() end animation |
abstract long |
getDuration() Get animation duration |
TimeInterpolator |
getInterpolator() Get the current animation's interpolator |
ArrayList<Animator.AnimatorListener> |
getListeners() Get the current listener list |
abstract long |
getStartDelay() Get the delay time before the animation starts |
long |
getTotalDuration() Get the total time of the current animation, including repeat time and delay time, etc. |
boolean |
isPaused() Returns whether the animation is paused |
abstract boolean |
isRunning() Returns whether the current animation is executing |
boolean |
isStarted() Returns whether the current animation starts to execute |
void |
pause() Pauses a running animation. |
void |
removeAllListeners() remove all listeners |
void |
removeListener(Animator.AnimatorListener listener) remove the specified listener |
void |
removePauseListener(Animator.AnimatorPauseListener listener) remove pause monitor |
void |
resume() will pause the animation and continue execution |
abstract Animator |
setDuration(long duration) Set animation duration |
abstract void |
setInterpolator(TimeInterpolator value) set interpolator |
abstract void |
setStartDelay(long startDelay) Set a delay before the animation starts |
void |
setTarget(Object target) Set the object to perform animation |
void |
setupEndValues() Set the animation end value |
void |
setupStartValues() Set the animation start value |
void |
start() start this animation |
This is the first part. Regarding the underlying execution logic of attribute animation, I don’t understand enough to be reasonable. I will come back and rewrite it when the knowledge reserve is enough to understand this piece in the future. Old rules, code address: github
welcome to my blog to discuss related issues~