Full parsing of Android property animation (bottom), Interpolator and ViewPropertyAnimator usage, interpolator

Source: Internet
Author: User

Full parsing of Android property animation (bottom), Interpolator and ViewPropertyAnimator usage, interpolator

Reprinted please indicate the source: http://blog.csdn.net/guolin_blog/article/details/44171115

Hello everyone, welcome to continue to complete parsing of the Android property animation. In the previous article, we learned some advanced techniques of property animation, including the advanced usage of ValueAnimator and ObjectAnimator. In addition, there are also some other advanced skills waiting for us to learn, therefore, this article takes an end to completely parsing the entire attribute animation series to learn the most important advanced skills.

In addition, the code used in this article is based on the previous article. If you have not read the previous article, it is recommended to read it first.Android property animation full parsing (medium), ValueAnimator, and ObjectAnimator advanced usage.

Interpolator usage

Interpolator is very difficult to translate. If it is literally translated, it means the Interpolator. Its main function is to control the animation change rate, for example, to achieve an animation effect of a non-linear motion. So what is the animation effect of Nonlinear Motion? That is to say, the speed at which an animation changes is not static. acceleration and deceleration are both non-linear.

However, Interpolator is not a new technology in property animation. In fact, the Interpolator interface has existed since Android 1.0, and the previously completed animation also supports this function. However, a TimeInterpolator interface is added to the property animation. This interface is used to be compatible with the previous Interpolator, so that all the previous Interpolator implementation classes can be directly taken and used in the property animation, now let's take a look at all the implementation classes of the TimeInterpolator interface, as shown in:


As you can see, there are already many implementation classes for the TimeInterpolator interface. These are all built-in Android Interpolator that we can directly use. Each Interpolator has its own implementation effect. For example, AccelerateInterpolator is an Interpolator for accelerating motion, and DecelerateInterpolator is an Interpolator for slowing down motion.

I think careful friends should have already discovered that all the attribute animations we have learned in the previous two articles are not actually performing a thread movement. For example, the value printed by ValueAnimator in the previous article is as follows:


We can see that the initial value change speed is obviously slow. It is printed four times at the beginning of 0.0, and then acceleration starts, and the last phase starts to slow down again, therefore, we can clearly see this Interpolator that accelerates first and then slows down.

Next, let's take a look at the small ball moving and color changing function completed in the "medium" article, as shown in:


From this we can see that the ball starts to slow, and then gradually accelerates, the middle part of the speed is relatively fast, then start to slow down, and finally stop slowly. In addition, the color change is also this pattern. The color changes slowly at the beginning, the middle color changes quickly, and the color changes slowly at the last stage.

We can draw a conclusion from the above points. When using attribute animation, the default system Interpolator is actually an Interpolator that accelerates and slows down. The corresponding implementation class is AccelerateDecelerateInterpolator.

Of course, we can easily modify this default attribute and replace it with any built-in Interpolator. Let's take the code in the "medium" article as an example. The startAnimation () method in MyAnimView is the entry to enable the animation effect. Here we will slightly modify the coordinates of the Point object, the Code is as follows:

private void startAnimation() {    Point startPoint = new Point(getWidth() / 2, RADIUS);    Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {        @Override        public void onAnimationUpdate(ValueAnimator animation) {            currentPoint = (Point) animation.getAnimatedValue();            invalidate();        }    });    anim.setDuration(2000);    anim.start();}
Here, the coordinate value in the Point constructor is changed. Now, the animation effect of the ball movement should be falling from the top of the center of the screen to the bottom. However, by default, the decrease speed of a ball must be accelerated first and then slowed down. This is not in line with the common knowledge of physics. If the ball is regarded as a free fall, then the speed of decline should be faster and faster. How can we change this default behavior? In fact, it is very easy to call the setInterpolator () method of Animator. This method requires the input of an instance that implements the TimeInterpolator interface. For example, if we want to achieve faster and faster ball drops, you can use AccelerateInterpolator. The Code is as follows:
private void startAnimation() {    Point startPoint = new Point(getWidth() / 2, RADIUS);    Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {        @Override        public void onAnimationUpdate(ValueAnimator animation) {            currentPoint = (Point) animation.getAnimatedValue();            invalidate();        }    });    anim.setInterpolator(new AccelerateInterpolator(2f));    anim.setDuration(2500);    anim.start();}

The code is very simple. Here the setInterpolator () method is called, and an AccelerateInterpolator instance is passed in. Note that the AccelerateInterpolator construction function can receive a float parameter, which is used to control acceleration. Run the code, as shown in the following figure:


OK. The effect is very obvious. It means that the default Interpolator has been successfully replaced, and the AccelerateInterpolator has actually taken effect. However, the animation effect still looks strange, because a ball is still standing when it falls from a very high place to the ground, which is not in line with the physical law, after the ball hits the ground, it should rebound, then fall again, then rebound again, and then fall again. This repeats and finally stands still. Of course we can write this function by ourselves, but it is complicated. Fortunately, such an Interpolator has been provided in the Android system, we only need to replace it with a simple one to complete the effect described above. The Code is as follows:

private void startAnimation() {    Point startPoint = new Point(getWidth() / 2, RADIUS);    Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {        @Override        public void onAnimationUpdate(ValueAnimator animation) {            currentPoint = (Point) animation.getAnimatedValue();            invalidate();        }    });    anim.setInterpolator(new BounceInterpolator());    anim.setDuration(3000);    anim.start();}
We can see that we only change the set Interpolator to the BounceInterpolator instance, while BounceInterpolator is an Interpolator that can simulate physical laws and achieve repeated effects. In addition, the overall animation time is slightly extended because it takes a longer time to repeatedly play the ball than before. Run the code again, as shown in the following figure:


OK! The results are quite good. Here we just selected several well-implemented interpolators. Since there are many built-in interpolators, we will not explain them one by one. You can use several other interpolators to see the effect.

However, we only use the Interpolator provided by the system. Obviously, our requirements for ourselves are too low. Since we are learning the advanced usage of property animation, we naturally need to thoroughly study it. Next, let's take a look at the internal implementation mechanism of Interpolator and try to write a custom Interpolator.

First, let's take a look at the Interface Definition of TimeInterpolator. The Code is as follows:

/** * A time interpolator defines the rate of change of an animation. This allows animations * to have non-linear motion, such as acceleration and deceleration. */public interface TimeInterpolator {    /**     * Maps a value representing the elapsed fraction of an animation to a value that represents     * the interpolated fraction. This interpolated value is then multiplied by the change in     * value of an animation to derive the animated value at the current elapsed animation time.     *     * @param input A value between 0 and 1.0 indicating our current point     *        in the animation where 0 represents the start and 1.0 represents     *        the end     * @return The interpolation value. This value can be more than 1.0 for     *         interpolators which overshoot their targets, or less than 0 for     *         interpolators that undershoot their targets.     */    float getInterpolation(float input);}

OK, the interface is still very simple. There is only one getInterpolation () method. If you are interested, you can use annotations to understand this interface in detail. Here I will briefly explain that the getInterpolation () method receives an input parameter, the value of this parameter will change with the running of the animation, but its changes are irregular, that is, it increases at a constant speed according to the preset animation length, and the change range is 0 to 1. That is to say, when the animation starts, the input value is 0, and when the animation ends, the input value is 1, the value in the middle changes with the animation running duration between 0 and 1.

Speaking of the input value, I think many may think of the fraction value we used in the "Middle" article. So what is the relationship between input and fraction? The answer is simple. The input value determines the fraction value. The input value is passed in to the getInterpolation () method after calculation by the system. Then, we can implement the algorithm in the getInterpolation () method and calculate a return value based on the input value, the returned value is fraction.

Therefore, the simplest case is that the input value and fraction value are the same. In this case, because the input value increases at a constant speed, the fraction value increases at a constant speed, therefore, the motion of the animation is also constant. The built-in LinearInterpolator in the system is an Interpolator with a uniform motion. Let's take a look at how its source code is implemented:

/** * An interpolator where the rate of change is constant */@HasNativeInterpolatorpublic class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {    public LinearInterpolator() {    }    public LinearInterpolator(Context context, AttributeSet attrs) {    }    public float getInterpolation(float input) {        return input;    }    /** @hide */    @Override    public long createNativeInterpolator() {        return NativeInterpolatorFactoryHelper.createLinearInterpolator();    }}

Here we only look at the getInterpolation () method. This method has no logic, that is, it directly returns the input value passed in the parameter. Therefore, the fraction value is equal to the input value, this is the implementation of the Interpolator with a uniform motion.

Of course, this is the simplest implementation of Interpolator. Let's look at a little more complicated. Now that we all know that the system uses AccelerateDecelerateInterpolator by default, let's take a look at its source code, as shown below:

/** * An interpolator where the rate of change starts and ends slowly but * accelerates through the middle. *  */@HasNativeInterpolatorpublic class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {    public AccelerateDecelerateInterpolator() {    }        @SuppressWarnings({"UnusedDeclaration"})    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {    }        public float getInterpolation(float input) {        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;    }    /** @hide */    @Override    public long createNativeInterpolator() {        return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();    }}
Although the Code does not get much longer, the logic in the getInterpolation () method has become much more complex. Instead of simply returning the input in the parameter, it performs a more complex mathematical operation. Here we will analyze its algorithm implementation. We can see that the algorithm mainly uses the cosine function, because the input value ranges from 0 to 1, then the value range of the cos function is π to 2π. The result of cos (π) is-1, and the result of cos (2 π) is 1. Then the value is divided by 2 and 0.5, and getInterpolation () the final result value returned by the method is still between 0 and 1. However, after the cosine operation, the final result is no longer increasing at a constant speed, but is a process of first accelerating and then slowing down. We can plot the execution of this algorithm through a curve, as shown in the result:


We can see that this is an S-type curve. When the x-axis changes from 0 to 0.2, the variation of the Y-axis is very small, but then it starts to accelerate significantly, at last, when the x-axis changes from 0.8 to 1, the variation of the x-axis becomes very small.

OK. By analyzing the source code of LinearInterpolator and AccelerateDecelerateInterpolator, we have a clear understanding of the internal implementation mechanism of Interpolator. Next we will try to write a custom Interpolator.

The most important difficulty in writing custom Interpolator is in mathematics computing. Because I am not very good at mathematics, I will write a simple Interpolator here to show it to you. Since the default attribute animation Interpolator is a method of acceleration first and then deceleration, we will make a simple modification to it to make it become a method of acceleration after deceleration. Create the DecelerateAccelerateInterpolator class to implement the TimeInterpolator interface. The Code is as follows:

public class DecelerateAccelerateInterpolator implements TimeInterpolator{    @Override    public float getInterpolation(float input) {        float result;        if (input <= 0.5) {            result = (float) (Math.sin(Math.PI * input)) / 2;        } else {            result = (float) (2 - Math.sin(Math.PI * input)) / 2;        }        return result;    }}
This Code uses the sine function to implement the feature of first slowing down and then accelerating, because the variation value of the sine function's initial radians is very large, just opposite to the cosine function, with the increase of radians, the variable value of the sine function will gradually decrease, thus achieving the deceleration effect. When the radians are greater than π/2, the entire process is reversed. Now, the radians of the sine function have a very small variation value. As the radians continue to increase, the variation value increases, the radians end at π, so that from 0 to π, the effect of first slowing down and then accelerating is achieved.

Similarly, we can plot the execution of this algorithm through a curve, as shown in the result:


We can see that this is also an S-type curve, but the direction of the curve is the opposite. From this we can clearly see that at the beginning, the ordinate variation was very large, and then gradually became smaller. When the abscissa reached 0.5, the ordinate variation was almost zero, then, as the X-axis increases, the variation of the x-axis increases again, which is indeed the effect of first slowing down and then accelerating.

Now we will replace DecelerateAccelerateInterpolator in the code, as shown below:

private void startAnimation() {    Point startPoint = new Point(getWidth() / 2, RADIUS);    Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {        @Override        public void onAnimationUpdate(ValueAnimator animation) {            currentPoint = (Point) animation.getAnimatedValue();            invalidate();        }    });    anim.setInterpolator(new DecelerateAccelerateInterpolator());    anim.setDuration(3000);    anim.start();}

It is very simple to pass the DecelerateAccelerateInterpolator instance to the setInterpolator () method. Run the code again, as shown in the following figure:


OK! The movement of the ball is indeed the effect of first slowing down and then accelerating, indicating that our custom Interpolator can work normally. Through such a learning, I believe that everyone's understanding and use of attribute animation Interpolator have reached a deep level.

ViewPropertyAnimator usage

ViewPropertyAnimator is actually not an advanced technique. Its usage is extremely simple, but it is not introduced in the 3.0 system because it is different from the previous knowledge of property animation, instead, we add a new feature to the 3.1 system, so we use it as the final part of the entire property animation series.

We all know that the property animation mechanism is no longer designed for View, but a mechanism that constantly operates on values, it can assign values to the specified attributes of a specified object. However, in most cases, I believe that most people still animation views. The Android development team also realized this and did not provide a more convenient usage for View animation operations. It is indeed a little too unfriendly, therefore, ViewPropertyAnimator is added to the Android 3.1 system.

Let's review the previous usage. For example, if we want to change a TextView from a regular state to a transparent state, we can write it like this:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);animator.start();
Does it look complicated? It seems not complicated, but it is not easy to understand. We need to pass the view, attribute, and changed values of the operation to ObjectAnimator. although the ofFloat () method does not seem to have written a few lines of code, it is not like the object-oriented thinking we usually use.

Next, let's take a look at how to use ViewPropertyAnimator to achieve the same effect. ViewPropertyAnimator provides an API that is easier to understand and more object-oriented, as shown below:

textview.animate().alpha(0f);

It's really easy! But what is the problem with textview. animate? The animate () method is a new method added on the Android 3.1 system. The returned value of this method is a ViewPropertyAnimator object, that is to say, after obtaining this object, we can call its various methods to achieve the animation effect. Here we call the alpha () method and transfer it to 0, which indicates that the current textview is transparent.

How is it? ViewPropertyAnimator is easier to understand than ObjectAnimator. In addition, ViewPropertyAnimator can easily combine multiple animations. For example, if we want to make textview move to the coordinate point 500,500, we can write it like this:

textview.animate().x(500).y(500);
We can see that ViewPropertyAnimator supports the concatenation function. We want to call the method x (500) when moving textview to the position of x coordinate 500, then, when the textview is moved to the ordinate position 500, the y (500) method is called to concatenate all the animations to be combined using this concatenation method, in this way, all the animations will be executed together.

How can we set the animation running duration? It is very simple. You can set it by means of concatenation. For example, if you want to run the animation for five seconds, you can write it like this:

textview.animate().x(500).y(500).setDuration(5000);
In addition, the Interpolator technology we have learned in the first part of this article can also be applied to ViewPropertyAnimator, as shown below:
textview.animate().x(500).y(500).setDuration(5000).setInterpolator(new BounceInterpolator());
It is easy to use, and it also uses the concatenation method. I believe everyone has already experienced it. ViewPropertyAnimator doesn't actually have many skills, and its usage is basically the same. If you need any features, you can link them up, for more usage, you only need to refer to the document to see which functions are supported and which interfaces can be called.

In addition to usage, there are several details about ViewPropertyAnimator, which are worth your attention:

  • The entire ViewPropertyAnimator function is built on the newly added animate () method of the View class. This method creates and returns a ViewPropertyAnimator instance, and all subsequent methods called, all properties set are completed through this instance.
  • When ViewPropertyAnimator is used, we did not call the start () method from start to end. This is because the new interface uses the implicit animation startup function. After we define the animation, the animation is automatically started. This mechanism is also effective for composite animations. As long as we continuously attach new methods, the animation will not be executed immediately. After all the methods set on ViewPropertyAnimator are executed, the animation is automatically started. Of course, if you do not want to use this default mechanism, you can also explicitly call the start () method to start the animation.
  • All interfaces of ViewPropertyAnimator are designed using the concatenation syntax. the return value of each method is its own instance. Therefore, after calling a method, you can directly concatenate and call another method, in this way, we can concatenate all functions, and even complete the animation function of any complexity with only one line of code.

Okay. So far, the entire series of completely parsed Android property animations are all over. Thank you for your patience and patience.

Get a blog update reminder and share more technical information. Please follow my public account and scan the QR code or search for guolin_blog.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.