In-depth analysis of Property Animation (principles, source code, and practices)
Recently I want to try the ripple effect of Material Design, so I downloaded the material-ripple on github. The effect is good. Animation is used, of course, and has never been used before. Simply learn the animation.
Overall, I have referred to google's official documentation, Guo Dashen's analysis on Property Animation, and material-ripple's source code.
Therefore, the following three parts can be divided into three parts: "have an overall understanding", "understand its internal principles", and "how to practice"
1. google official documentation, good English look: http://developer.android.com/guide/topics/graphics/prop-animation.html#listeners, certainly better than I said.
The property animation will adapt the property value for a specific period of time. Property animation allows you to define the animation features:
Duration: Specifies the animation time. The default value is 300 ms;
Time interpolation: You can specify the attribute value at a certain Time point;
Repeat count and behavior: Specifies whether the animation is repeated or not;
Animator sets: an animation set that allows an animation to be superimposed or executed consecutively or in a delayed manner;
Frame refresh delay: specifies the number of animation frames refreshed. The default value is 10 ms.
Several Classes are important:
ValueAnimator: Specifies the animation timing, and calculates the attribute value of the time.
At the same time, ValueAnimator includes TimeInterpolator and TypeEvaluator. As the name suggests, TimeInterpolator can be understood as an "insertor" to insert an animation. It can be linear or non-linear (for exampleAccelerateDecelerateInterpolator
)
During the animation, ValueAnimator is responsible for calculating the elapsed fraction, that is, the past time factor. If the time has passed 1/4, the elapsed fraction is 0.25;
After elapsed fraction is calculated, interpolated fraction is calculated by TimeInterpolator Based on the elapsed fraction, that is, the insertion factor. For a linear TimeInterpolator, it should be the same as elapsed fraction. If it is not linear, for exampleAccelerateDecelerateInterpolator
So it is different from elapsed fraction (0.15 ).
After interpolated fraction is calculated, ValueAnimator allows the TypeEvaluator to calculate the animation attribute value.
All in all, the attribute values for a frame refresh time are related to the animation start and end values, the elapsed time, And the inserter types.
API Overview:
1. When using animations, we should use the sub-class of Animator:
ValueAnimator: Calculate the attribute value, as mentioned earlier. However, it should be noted that the property animation should contain two parts: 1. calculate the property value, 2. assign the calculated attribute value to the attribute, but ValueAnimator does not assign values. Therefore, you should assign values to the attribute yourself.
ObjectAnimator: a subclass of ValueAnimator. Compared with ValueAnimator, it has the advantage that attributes are assigned after the attribute value is calculated. Commonly used ObjectAnimator ~
AnimatorSet: Specifies an animation set that allows an animation to be superimposed, contiguous, or delayed.
2. Evaluators: calculates the attribute value. Includes the following types:
IntEvaluator: the default evaluator of the int attribute;
FloatEvaluator: the default evaluator of the float attribute;
ArgbEvaluator: default color attribute evaluator (hexadecimal color );
TypeEvaluator: it is an interface for custom type Evaluator. If your attributes are not int, float, or color, you must use a custom type Evaluator.
3. Interpolators: A time interpolator defines how specific values in an animation are calculated as a function of time. (how good is definition ~), The following classes are not mentioned: AccelerateDecelerateInterpolator (slow at both ends, fast in the middle), LinearInterpolator, TimeInterpolator (interface, used for custom Interpolator)
Use ValueAnimator
As mentioned above, when calculating the attribute value, it must be based on three points: "animation start and end values", "elapsed time", and "inserter.
The "elapsed time" is of course based on the frame refresh rate, so there must be two other points during ValueAnimator initialization.
1.
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);animation.setDuration(1000);animation.start();
2.
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);animation.setDuration(1000);animation.start();
As mentioned above, ValueAnimator has a disadvantage that it cannot assign values. You need to add the assignment logic yourself. What should I do?
You can set a listener for ValueAnimator.GetAnimatedValue () to get the property value. The details are described below.
Use ObjectAnimator
This is common because you do not need to set up listeners.ValueAnimator.AnimatorUpdateListener
Because the property is updated automatically.
The initialization of ObjectAnimator is similar to the initialization of ValueAnimator, but an object needs to be created, and the attribute name (String), for example:
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);anim.setDuration(1000);anim.start();
To update ObjectAnimator attributes correctly, you need to do the following:
1. set the set Method (to assign values to attributes ~) If the property name is aaa, the set method is setAaa (). If you cannot directly set the set method, you can try to set a packaging class (this is what material-ripple does). If not, you can only use ValueAnimator;
2. If there is only one value for the value array values (each value is the same as it was at the beginning), then each update should have a get method;
3. The property value type of the getter (if needed) and setter operations should be consistent with the start value and end value, which is easy to understand.
4. for a view change display, we should call invalidate at each animation Update (callback onAnimationUpdate) (if it is a color change, call the setters method, invalidate not required)
Use AnimatorSet
It can be simultaneously, sequentially, or after a specified delay.
The following is an example:
- Plays
bounceAnim
.
- Plays
squashAnim1
,squashAnim2
,stretchAnim1
, AndstretchAnim2
At the same time.
- Plays
bounceBackAnim
.
- Plays
fadeAnim
.AnimatorSet bouncer = new AnimatorSet();bouncer.play(bounceAnim).before(squashAnim1);bouncer.play(squashAnim1).with(squashAnim2);bouncer.play(squashAnim1).with(stretchAnim1);bouncer.play(squashAnim1).with(stretchAnim2);bouncer.play(bounceBackAnim).after(stretchAnim2);ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);fadeAnim.setDuration(250);AnimatorSet animatorSet = new AnimatorSet();animatorSet.play(bouncer).before(fadeAnim);animatorSet.start();
Animation listener Animation Listeners
It is relatively simple. paste the original text directly.
nimator.AnimatorListener
onAnimationStart()
-Called when the animation starts.
onAnimationEnd()
-Called when the animation ends.
onAnimationRepeat()
-Called when the animation repeats itself.
onAnimationCancel()
-Called when the animation is canceled. A canceled animation also CILSonAnimationEnd()
, Regardless of how they were ended.
ValueAnimator.AnimatorUpdateListener
onAnimationUpdate()
-Called on every frame of the animation. Listen to this event to use the calculated values generatedValueAnimator
During an animation. To use the value, queryValueAnimator
Object passed into the event to get the current animated value withgetAnimatedValue()
Method. Implementing this listener is required if you useValueAnimator
.
Depending on what property or object you are animating, you might need to callinvalidate()
On a View to force that area of the screen to redraw itself with the new animated values. for example, animating the color property of a Drawable object only cause updates to the screen when that object redraws itself. all of the property setters on View, suchsetAlpha()
AndsetTranslationX()
Invalidate the View properly, so you do not need to invalidate the View when calling these methods with new values.
You can extendAnimatorListenerAdapter
Class instead of implementingAnimator.AnimatorListener
Interface, if you do not want to implement all of the methods ofAnimator.AnimatorListener
Interface.AnimatorListenerAdapter
Class provides empty implementations of the methods that you can choose to override.
For example, the Bouncing bils sample in the API demos createsAnimatorListenerAdapter
For justonAnimationEnd()
Callback:
ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);fadeAnim.setDuration(250);fadeAnim.addListener(new AnimatorListenerAdapter() {public void onAnimationEnd(Animator animation) { balls.remove(((ObjectAnimator)animation).getTarget());}