catalogue
- 1. Classification of animation
- 2. Why can’t tween animation really change the position of a View? Why does property animation work? How does a property animation change the properties of a View?
- 3. What are the functions of property animation interpolators and estimators? How do the interpolator and estimator change the animation, respectively?
- 4. Why does the property animation end up changing the View’s click event position but the View animation does not?
- 5. Cause of memory leak of property animation
- 6. Specific usage
1. Classification of animation
- Property animation: Animate this class of objects to really change the properties of the object. (ObjectAnimator, ValueAnimator)
- Frame animation: the animation effect constructed by a frame of pictures, frame animation should pay attention to the picture will be OOM.
- Tween animation (View animation): The View pan, zoom, rotate and transparency changes of the animation, can not really change the position of the View, relatively large restrictions and only four kinds of animation
AlphaAnimation, RotateAnimation, ScaleAnimation, TranslateAnimation
And it only works on View. (Apps such as Activity toggle animations)
2. Why can’t tween animation really change the position of a View? Why does property animation work? How does a property animation change the properties of a View?
- The View animation
All that changes is the canvas of the View
, without changing the click response area of the View; The property animation will use reflection technology to obtain and execute the property of get, set methods, soChanged the value of an attribute in the position of an object
. - The Animation data generated by the Animation is not actually applied to the View itself, but to the RenderNode or Canvas (animated by moving the Canvas). This is the fundamental reason why the Animation does not change the properties of the View. We can understand for Animation only operation View canvas is not to change the position of the View (, mRight mLeft, mTop, mBottom).
In View’s draw() method:
final Animation a = getAnimation(); // Whether the animation is setif(a ! = null) { more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); concatMatrix = a.willChangeTransformationMatrix();if (concatMatrix) {
mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
}
transformToApply = parent.getChildTransformation();
} else {
if((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) ! = 0) { // No longer animating: clear out old animation matrix mRenderNode.setAnimationMatrix(null); mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; }if(! drawingWithRenderNode && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ! = 0) { final Transformation t = parent.getChildTransformation(); final boolean hasTransform = parent.getChildStaticTransformation(this, t);if(hasTransform) { final int transformType = t.getTransformationType(); transformToApply = transformType ! = Transformation.TYPE_IDENTITY ? t : null; concatMatrix = (transformType & Transformation.TYPE_MATRIX) ! = 0; }}}...if(transformToApply ! = null) {if (concatMatrix) {
if (drawingWithRenderNode) {
renderNode.setAnimationMatrix(transformToApply.getMatrix());
} else {
// Undo the scroll translation, apply the transformation matrix,
// thenredo the scroll translate to get the correct result. canvas.translate(-transX, -transY); canvas.concat(transformToApply.getMatrix()); canvas.translate(transX, transY); } parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; }... }Copy the code
In View’s draw method we can see that when we set the animation, the transformToApply object is generated. When the transformToApply object is not null, the View is redrawn according to the parameter matrix of the animation. It is important to note that the Animation data generated by the Animation is not actually applied to the View itself, but to the RenderNode or Canvas. This is the fundamental reason why Animation does not change the properties of the View. On the other hand, we know that the Animation is only useful when the View is drawn, which is why the tween Animation is included in the Android.View package.
3. What are the functions of property animation interpolators and estimators? How do the interpolator and estimator change the animation, respectively?
-
Interpolator: Calculates the percentage change in the value of a current property based on the percentage of time elapsed. Determine the mode of animation effect change, such as uniform change, accelerated change and so on. View animation and property animation can be used. (It can be understood as changing the speed curve of the animation. By default, the interpolator is used to speed up and then slow down.)
-
Common system built-in interpolators:
- LinearInterpolator: uniform animation
- Acceleration deceleration interpolation (AccelerateDecelerateInterpolator) : animation two head of slow and fast
- DecelerateInterpolator: animation gets slower and slower
A custom Interpolator implements the Interpolator interface.
public class LinearInterpolator implements Interpolator {
public LinearInterpolator() {
}
public LinearInterpolator(Context context,AttributeSet attrs) {
}
public float getInterpolation(float input) {
returninput; }}Copy the code
-
TypeEvaluator: calculates the changed property value based on the percentage of the current property change (calculates what value to return at what percentage). For property animations, View animations do not require a type estimator. Commonly used system built-in estimators:
- Integer valuator
- Floating-point evaluator
- ArgbEvaluator Color attribute Valuator
A custom evaluator implements the TypeEvaluator interface.
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(floatfraction,Integer startValue,Integer endValue) { int startInt = startValue; Start :1,end:3 = 1+(3-1)*0.2return(int)(startInt + fraction * (endValue -startInt)); }}Copy the code
4. Why does the property animation end up changing the View’s click event position but the View animation does not?
Here’s an example:
mView.setOnTouchListener(new View.OnTouchListener() {
int lastX, lastY;
Toast toast = Toast.makeText(TestActivity.this, "", Toast.LENGTH_SHORT);
@Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
if(event.getAction() == motionEvent.action_move) {//Toolbar and status bar height int toolbarHeight = (getWindow().getDecorView().getHeight() - findViewById(R.id.root_view).getHeight()); int widthOffset = mView.getWidth() / 2; int heightOffset = mView.getHeight() / 2; mView.setTranslationX(x - mView.getLeft() - widthOffset); mView.setTranslationY(y - mView.getTop() - heightOffset - toolbarHeight); toast.setText(String.format("left: %d, top: %d, right: %d, bottom: %d",
mView.getLeft(), mView.getTop(), mView.getRight(), mView.getBottom()));
toast.show();
}
lastX = x;
lastY = y;
return true; }});Copy the code
When we call methods like setTranslationX or setRotation, it’s not the View position that changes, it’s the View canvas that changes. The view.layout() method is the only way to change the View’s real coordinates. Why can a property animation change the View’s click area with setTranslationX?
Because when we went to determine whether the View in the event distribution when in the area of the finger to judge whether the View invokes the setTranslation, setRotation, setScale these methods, if call invokes the matrix. The mapPoints will be at the beginning of the View of this method Coordinate values in the beginning and after the animation to change the coordinate values of a fusion calculation to get the final View coordinates, this value to judge whether the View then click on the area, and complement between animation did not set the matrix to View, then eventually do when natural not to merge their coordinates change after coordinates to determine whether the View in the finger click area, So a View animation doesn’t change the click area whereas a property animation does.
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
......
Transformation transformToApply = null;
final Animation a = getAnimation();
if(a ! = null) { more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); transformToApply = parent.getChildTransformation(); }if(transformToApply ! = null) {if(drawingWithRenderNode) {/ / attribute animation sets matrices renderNode. SetAnimationMatrix (transformToApply. GetMatrix ()); }else{ canvas.translate(-transX, -transY); / / the View won't be set animation to canvas in the matrix. The concat (transformToApply. GetMatrix ()); canvas.translate(transX, transY); }}}Copy the code
When we set the animation to play the tween animation, the changes we see are only temporary. Property animation, on the other hand, what it changes is updated to the matrix corresponding to the View, so when the ViewGroup dispatches the event, it correctly converts the current touch coordinates to the matrix changed coordinates, which is why playing the tween animation doesn’t change the touch area.
5. Cause of memory leak of property animation
public AnimationHandler getAnimationHandler() { returnAnimationHandler.getInstance(); } private void addAnimationCallback(long delay) {if(! mSelfPulse) {return; } getAnimationHandler().addAnimationFrameCallback(this, delay); This is ValueAnimator itself}Copy the code
For example, when we create a ValueAnimator, we create a static AnimationHandler class that holds ValueAnimator. When we enter the Activity screen, if we have some property animation bound to the control running in infinite loop mode, Remember to cancel these animations when you exit or you’ll cause a memory leak.
Activity->View->ValueAnimator->AnimationHandler (static class,GCROOT)
public void startAnimation(Animation animation) {
animation.setStartTime(Animation.START_ON_FIRST_FRAME);
setAnimation(animation);
invalidateParentCaches();
invalidate(true);
}
Copy the code
6. Specific usage
Reference: github.com/lvzishen/LV…
It includes examples of various types of animation use, keyframes and so on. Below is an example of the use of property animation
ValueAnimator mFirstPhaseAnimator;
if (mFirstPhaseAnimator == null) {
mFirstPhaseAnimator = ValueAnimator.ofInt(0, 100);
mFirstPhaseAnimator.setDuration(2000);
mFirstPhaseAnimator.setInterpolator(new DecelerateInterpolator());
mFirstPhaseAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
if(! mIsAnimationSetFinished) { mCurrentVal = (int) valueAnimator.getAnimatedValue(); Gets the current valueif(mProcessor ! = null) { String text = mProcessor.getText(getContext(), mCurrentVal);if (TextUtils.isEmpty(text)) {
setValText(text); }}else {
setValText(String.valueOf(mCurrentVal)); }}}}); mFirstPhaseAnimator.start(); // Start animation}Copy the code