Attribute animation of Android animation collection -- see also

Introduction to this section:

In the last section, we made a preliminary study of Android attribute animation. I believe that everyone is no longer in a state of half-knowledge about attribute animation. In this section, we will continue to explore some more advanced usages of Android attribute animation!


1. Evaluator customization

1) Introduction to Evaluator

The attribute animation of the Android animation collection in the previous section -- at first sight , the first step in using animation is:

Call ValueAnimator's ofInt (), ofFloat () or ofObject () static method to create a ValueAnimator instance!

In the example, we use both ofInt and ofFloat, which are used to animate floating-point and integer data respectively!

So ofObject ()? Initial object and end object? How to transition law? Or how to use this thing?

Okay, with doubts, let’s first understand something: Evaluator. In fact, we talked about this thing when we talked about the concept of attribute animation:

Used to tell the animation system how to transition from the initial value to the end value ! OK, we're on the right track! Let's go into the source code of IntEvaluator and see what's written in it?

Well, the TypeEvaluator interface is implemented , and then the evaluate() method is rewritten . There are three parameters, in order:

  • fraction : The completion of the animation, we calculate the value of the animation based on it
  • startValue : the starting value of the animation
  • endValue : the end value of the animation

Animation value = initial value + degree of completion * (end value - initial value)

There is also FloatEvaluator, we want to tell the system how to transition from the initial object to the end object, then we have to implement the TypeEvaluator interface by ourselves, that is, customize the Evaluator, it is useless to talk about it, let’s write an example to see:

2) Example of use

Running effect diagram :

Code implementation :

Define an object Point.java , in which there are only two properties x, y and get, set methods~

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class Point {

    private float x;
    private float y;

    public Point() {
    }

    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }

    public void setX(float x) {
        this.x = x;
    }

    public void setY(float y) {
        this.y = y;
    }
}

Then customize the Evaluator class: PointEvaluator.java , and implement the interface to rewrite the evaluate method~

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class PointEvaluator implements TypeEvaluator<Point>{
    @Override
    public Point evaluate(float fraction, Point startValue, Point endValue) {
        float x = startValue.getX() + fraction * (endValue.getX() - startValue.getX());
        float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY());
        Point point = new Point(x, y);
        return point;
    }
}

Then customize a View class: AnimView.java , very simple~

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class AnimView extends View {

    public static final float RADIUS = 80.0f;
    private Point currentPoint;
    private Paint mPaint;

    public AnimView(Context context) {
        this(context, null);
    }

    public AnimView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AnimView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }

    private void drawCircle(Canvas canvas){
        float x = currentPoint.getX();
        float y = currentPoint.getY();
        canvas.drawCircle(x, y, RADIUS, mPaint);
    }

    private void startAnimation() {
        Point startPoint = new Point(RADIUS, RADIUS);
        Point endPoint = new Point(getWidth() - RADIUS, 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(3000l);
        anim.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }
}

Finally, instantiate this View at MainActivity.java ~

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new AnimView(this));
    }
}

3) Example enhanced version

On the basis of the above example, we add the color change when the circle moves~ Here we also use an ObjectAnimator to load the animation of the color change, we add multiple int colors to the View to control the color, and write getColor() and setColor( ) method, let’s define an Evaluator first~

Running effect diagram :

Implementation code :

ColorEvaluator.java

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class ColorEvaluator implements TypeEvaluator<Integer>{
    @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int alpha = (int) (Color.alpha(startValue) + fraction *
                (Color.alpha(endValue) - Color.alpha(startValue)));
        int red = (int) (Color.red(startValue) + fraction *
                (Color.red(endValue) - Color.red(startValue)));
        int green = (int) (Color.green(startValue) + fraction *
                (Color.green(endValue) - Color.green(startValue)));
        int blue = (int) (Color.blue(startValue) + fraction *
                (Color.blue(endValue) - Color.blue(startValue)));
        return Color.argb(alpha, red, green, blue);
    }
}

Then add a color, get and set method to the custom View; create an ObjectAnimator, and AnimatorSet, and then combine the animations together to get there. Just add something here. I’m afraid that readers will have problems, just build another View~

AnimView2.java

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class AnimView2 extends View {

    public static final float RADIUS = 80.0f;
    private Point currentPoint;
    private Paint mPaint;
    private int mColor;

    public AnimView2(Context context) {
        this(context, null);
    }

    public AnimView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AnimView2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }



    private void drawCircle(Canvas canvas){
        float x = currentPoint.getX();
        float y = currentPoint.getY();
        canvas.drawCircle(x, y, RADIUS, mPaint);
    }

    private void startAnimation() {
        Point startPoint = new Point(RADIUS, RADIUS);
        Point endPoint = new Point(getWidth() - RADIUS, 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();
            }
        });

        ObjectAnimator objectAnimator = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(),
                Color.BLUE, Color.RED);
        //The animation collection adds the previous two animations together, and plays them at the same time with
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(anim).with(objectAnimator);
        animatorSet.setStartDelay(1000l);
        animatorSet.setDuration(3000l);
        animatorSet.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }

    //color's get and set methods~
    public int getColor() {
        return mColor;
    }

    public void setColor(int color) {
        mColor = color;
        mPaint.setColor(color);
        invalidate();
    }
}

Then MainActivity, change AnimView to AnimView2 in setContentView~


2. Interpolator (interpolator)

Well, we talked about this stuff when we talked about tween animation~ I don’t know if you still have an impression?

Both the tween animation and property animation of the tweener above are available, and a new TimeInterpolator interface is added to the tween animation. This interface is used to be compatible with the previous Interpolator, which allows all past Interpolator implementation classes to be used directly. Use it in attribute animation! We can call the setInterpolator() method of the animation object to set different Interpolators!  We should point something first, let the ball fall from the top to the bottom in the middle of the screen~ Then we will call the following statement for our collection animation:  animatorSet.setInterpolator(new AccelerateInterpolator(2f)); to control acceleration~

Running effect :

It seems a bit unreasonable, it should bounce normally, let's try it with BounceInterpolator ~

Hehe, the effect is quite good. Of course, there are good Interpolators provided by more than N systems. You can try them one by one by yourself, so I won’t get entangled with you here~

Let's take a look:

1) The internal implementation mechanism of Interpolator

We first went to the source code of the TimeInterpolator interface and found that there is only one getInterpolation () method;

Simple explanation : The getInterpolation() method receives an input parameter. The value of this parameter will continue to change as the animation runs, but its change is very regular, that is, it increases at a constant speed according to the set animation duration, and the range of change is 0 to 1. That is to say, when the animation starts, the value of input is 0, and when the animation ends, the value of input is 1, and the value in the middle changes between 0 and 1 as the animation runs.

The input value here determines the value of fraction in our TypeEvaluator interface . The input value is calculated by the system and passed into the getInterpolation () method, and then we can implement the  algorithm in the getInterpolation () method by ourselves, and calculate a return value according to the input value, and this return value is fraction. .

We can look at the code in LinearInterpolator :

It has not been processed here to directly return the input value, that is, the value of fraction is equal to the value of input. This is the implementation method of the Interpolator of uniform motion! In fact, it is nothing more than a different algorithm, which involves some mathematics, and once again realizes the importance of mathematics, here is the source code of BounceInterpolator :

Don't ask me about the algorithm here, I don't know either, let's find something easier to understand: AccelerateDecelerateInterpolator

This Interpolator first accelerates and then decelerates:  (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f  algorithm understanding:

Solution: From the value range of input is [0,1], it can be concluded that the value range of the value in cos is [π,2π], and the corresponding values ​​are -1 and 1; then use this value to divide by 2 After adding 0.5, the range of the result value returned by the getInterpolation() method is still [0,1], and the corresponding graph is as follows:

So it is a process of first accelerating and then decelerating!

Well, the scumbags can't play anymore...

, the above is all moved from Uncle Guo's article... I want to quietly...

2) Custom Interpolator

Well, let’s worry about it later, write a custom Interpolator example first: Very simple, implement the TimeInterpolator interface, rewrite the getInterpolation method

The sample code is as follows

private class DecelerateAccelerateInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        if (input < 0.5) {
            return (float) (Math.sin(input * Math.PI) / 2);
        } else {
            return 1 - (float) (Math.sin(input * Math.PI) / 2);
        }
    }
}

Just call setInterpolator(new DecelerateAccelerateInterpolator()) and set it up~ I won’t map it due to space limitations~


3.ViewPropertyAnimator

A new function added to the system after 3.1 provides a more convenient usage for the animation operation of View! If it was before, to change a TextView from a normal state to a transparent state, it would be written like this:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);  
animator.start();

It is more understandable to use ViewPropertyAnimator to achieve the same effect:

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

It also supports continuous usage , combining multiple animations, setting duration, setting Interpolator, etc.~

textview.animate().x(500).y(500).setDuration(5000)  
        .setInterpolator(new BounceInterpolator());

The usage is very simple, just check the document when using it~, and there are a few details below to pay attention to!

  • The function of the entire ViewPropertyAnimator is based on the newly added animate() method of the View class. This method will create and return an instance of ViewPropertyAnimator. All subsequent methods and all properties set are completed through this instance. .
  • After the animation definition is completed using ViewPropertyAnimator , the animation will start automatically . And this mechanism is also effective for combined animations. As long as we continue to add new methods, the animation will not be executed immediately. After all the methods set on ViewPropertyAnimator are executed, the animation will start automatically. Of course, if we don't want to use this default mechanism, we can also explicitly call  the start () method to start the animation.
  • All interfaces of ViewPropertyAnimator are designed using concatenated syntax, and the return value of each method is its own instance , so after calling a method, you can directly concatenate and call its other method, so that all functions are serialized Then, we can even complete animation functions of arbitrary complexity with just one line of code.

Guess you like

Origin blog.csdn.net/leyang0910/article/details/131873441