In Android development, it is inevitable that we will use animation to handle various animation effects to meet the high standards of UI design. For more complex animations, we usually use the well-known open source library lottie-Android. You may be curious about how Lottie works, but that’s beyond the scope of this article. Google it if you’re interested

Property animation and tween animation basic writing

I once saw on the forum that a person moved the control using TranslateAnimation, and then found that clicking on the new position of the View did not respond to its own click event, but the previous position did. In fact, the tween animation simply moves, zooms, rotates, and fades the View visually without actually changing the View’s properties. ** But most of the time we want the View to respond to touch events in the same position and visual way, so after Android 3.0 we introduced property animation to solve this problem completely.

Maybe some of you don’t understand what code is a property animation and what code is a tween animation. Here’s a quick demonstration of shifting the View 500 px to the right.

You can animate properties in one of two ways.

ObjectAnimator.ofFloat(tv1, "translationX".0f, 500f)
                    .setDuration(1000)
                    .start()
// Or like this
tv1.animate().setDuration(1000).translationX(500f)
Copy the code

But with tween animation, and you want to achieve the same effect.

val anim = TranslateAnimation(0f, 500f, 0f, 0f)
anim.duration = 1000
anim.fillAfter = true    // Set the state to remain after animation
tv1.startAnimation(anim)
Copy the code

Note the use of property animation

For property animations, it is particularly important to note that the properties of the actions need to have set and GET methods, otherwise your ObjectAnimator actions will not work. As we know, the translationX property setting method of the View accepts a float value, so if you write the above operation as ofInt, it won’t work. For example:

ObjectAnimator.ofInt(tv1, "translationX".0.500)
                    .setDuration(1000)
                    .start()
Copy the code

For the properties we need to use but not written, for example, we customize a progress bar View, we need to show progress in real time, at this time we can define a property, and let it support set and GET, then outside the custom View can do property animation operations.

How property animation and tween animation work

Attribute animation

The working principle of attribute animation is very simple, in fact, in a certain time interval, by constantly changing the value, and constantly assign the value to the property of the object, so as to achieve the animation effect of the object on the property.

This property can be a property of any object.

ValueAnimator and ObjectAnimator are two very important classes for animating properties. The difference is that ValueAnimator first changes the value and then manually assigns the value to the properties of the object. Is to operate indirectly on object properties; The ValueAnimator class is essentially a mechanism for changing values.

The ObjectAnimator class changes the value and then automatically assigns it to the properties of the object to animate it; Is to operate directly on object properties; ObjectAnimator is more intelligent and automated.

Filling between animation

For tween animations, we might as well follow the source code to see what is being done.

/**
 * Start the specified animation now.
 *
 * @param animation the animation to start now
 */
public void startAnimation(Animation animation) {
    animation.setStartTime(Animation.START_ON_FIRST_FRAME);
    setAnimation(animation);
    invalidateParentCaches();
    invalidate(true);
}
Copy the code

You can see that the invalidate() method is very obvious, and it is clear that the execution of the tween animation directly causes the View to execute the onDraw() method. In general, the core essence of tween animation is the process of constantly changing and refreshing Matrix transformation within a certain duration.

Why can a property animation move a View and the target position respond to touch events?

This question comes from WanAndroid. Up until now, I thought that since the properties of the View were changed, all properties of the animated control should be the same as those of the control set directly in the animated position.

After reading “Chen Xiaoyuan” ‘s answer, IT suddenly occurred to me that although the View has changed its attributes, it has not changed the left, right, top and bottom attributes of the View, and these attributes precisely determine the touch area judgment of the ViewGroup.

tv1.animate().setDuration(1000).translationX(500f)
Copy the code

So, assuming that our View has been panned, why does clicking on a new position respond to the click event?

Read the “Chen Xiaoluan” answer, I incidentally in-depth a wave of source code, think must be shared with you in this.

We know that when the ViewGroup does not override the onInterceptTouchEvent() method for event interception, we must use its dispatchTouchEvent() method for event distribution. The condition that determines which of our sub-views responds to our touch events is that the position of our fingers must be within the boundary of this sub-view, which is the rectangular area formed by the four attributes left, right, top and bottom.

So, if our View has been animated with properties, now the finger responds to the touch position in a region other than the View’s left, right, top, and bottom properties, but the View magically responds to our click event.

/**
 * Returns a MotionEvent that's been transformed into the child's local coordinates.
 *
 * It's the responsibility of the caller to recycle it once they're finished with it.
 * @param event The event to transform.
 * @param child The view whose coordinate space is to be used.
 * @return A copy of the the given MotionEvent, transformed into the given View's coordinate
 *         space.
 */
private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {
    final float offsetX = mScrollX - child.mLeft;
    final float offsetY = mScrollY - child.mTop;
    final MotionEvent transformedEvent = MotionEvent.obtain(event);
    transformedEvent.offsetLocation(offsetX, offsetY);
    if(! child.hasIdentityMatrix()) { transformedEvent.transform(child.getInverseMatrix()); }return transformedEvent;
}

/**
 * Returns true if the transform matrix is the identity matrix.
 * Recomputes the matrix if necessary.
 *
 * @return True if the transform matrix is the identity matrix, false otherwise.
 */
final boolean hasIdentityMatrix(a) {
    return mRenderNode.hasIdentityMatrix();
}

/**
 * Utility method to retrieve the inverse of the current mMatrix property.
 * We cache the matrix to avoid recalculating it when transform properties
 * have not changed.
 *
 * @return The inverse of the current matrix of this view.
 * @hide* /
public final Matrix getInverseMatrix(a) {
    ensureTransformationInfo();
    if (mTransformationInfo.mInverseMatrix == null) {
        mTransformationInfo.mInverseMatrix = new Matrix();
    }
    final Matrix matrix = mTransformationInfo.mInverseMatrix;
    mRenderNode.getInverseMatrix(matrix);
    return matrix;
}	
Copy the code

The original,ViewGroupgetTransformedMotionEvent()The method passes subsViewhasIdentityMatrix()Method to judge the subViewWhether attributes such as displacement, scaling, rotation, etc. have been applied to animation. If applied, the child will be calledViewgetInverseMatrix()Do the “reverse translation” operation, and then judge whether the processed touch point is in the childViewWithin the bounds of.

I have to say that Hongyang’s WanAndroid has brought us a lot of things. What is more amazing is that “Chen Xiaoyuan” has a very strong knowledge base in View. It is no wonder that he can write a customized View with strong standards.

Those who are eager to know more about View can go to Xiao Yuan’s blog to find out. me.csdn.net/u011387817