Easy Tutorial
❮ Web Image Optimization Ubuntu Modify Dns ❯

8.4.4 Android Animation Collection - Property Animation - Revisited

Category Android Basic Entry Tutorial

Introduction:

In the previous section, we had an initial learning session on Android's property animation. I believe that everyone is no longer in a state of knowing just the basics about property animation. In this section, we will continue to explore some more advanced uses of Android's property animation! Let's still refer to Guo Shen's three articles:

Android Property Animation Complete Guide (Part 1), Basic Usage of Property Animation

Android Property Animation Complete Guide (Part 2), Advanced Usage of ValueAnimator and ObjectAnimator

Android Property Animation Complete Guide (Part 3), Usage of Interpolator and ViewPropertyAnimator

The content is still based on the above three articles. Okay, let's start this section's content:


1. Custom Evaluator

1) Evaluator Introduction

In the previous section 8.4.3 Android Animation Collection - Property Animation - First Encounter, the first step in using the animation was:

Calling the ofInt(), ofFloat(), or ofObject() static methods of ValueAnimator to create a ValueAnimator instance!

In the example, we used both ofInt and ofFloat, which are used for animating floating-point and integer data types respectively.

So, what about ofObject()? Initial object and end object? How is the transition done? Or how is this thing used?

Alright, with these questions in mind, let's first understand something: Evaluator. In fact, we mentioned this thing in the babbling about property animation concepts:

It tells the animation system how to transition from the initial value to the end value. Okay, our entry point is correct! Let's look at the source code of IntEvaluator to see what's inside:

It implements the TypeEvaluator interface and overrides the evaluate() method, which has three parameters, namely:

-fraction: The completion degree of the animation, based on which we calculate what the animated value should be.

-startValue: The starting value of the animation.

-endValue: The ending value of the animation.

Animated value = initial value + completion degree * (end value - initial value)

Similarly, there is also FloatEvaluator. If we want to tell the system how to transition from the initial object to the end object, then we need to implement the TypeEvaluator interface ourselves, that is, to customize the Evaluator. Talking too much is useless, let's write an example to see:

2) Usage Example

Running Effect Diagram:

Code Implementation:

Define an object Point.java, which only has x and y attributes and their get and 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, implement the interface and override 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, which is 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 in MainActivity.java:

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

3) Enhanced Example

Based on the above example, let's add color changes during the circle's movement. Here, we use another ObjectAnimator to load the color change animation. We add an int color to control the color in the View, and write getColor() and setColor() methods. Let's first customize an Evaluator:

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);
    }
}
(Color.blue(endValue) - Color.blue(startValue)));
        return Color.argb(alpha, red, green, blue);
    }
}

Then add a color getter and setter method in the custom View; create an ObjectAnimator and an AnimatorSet, and then combine the animations together. Just adding a few things here, in case the reader has questions, let's create a new View directly.

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 set combines the previous two animations to play simultaneously
        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);
        }
    }

    // Getter and setter methods for color
    public int getColor() {
        return mColor;
    }

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

Then in MainActivity, change the setContentView to use AnimView2 instead of AnimView.


2. Interpolator (Interpolator)

Yes, we mentioned this when talking about tween animation. Do you still remember?

The interpolators mentioned above can be used for both tween animation and property animation. Tween animation also introduced a new TimeInterpolator interface, which is used to be compatible with the previous Interpolator, allowing all previous Interpolator implementation classes to be used directly in property animation. We can call the setInterpolator() method of the animation object to set different Interpolators. Let's make a few changes to make the ball fall from the top center of the screen to the bottom. Then we will call the following statement for our set animation: animatorSet.setInterpolator(new AccelerateInterpolator(2f)); The value in the parentheses controls the acceleration.

Running effect:

It seems a bit unreasonable. Normally, it should bounce, right? Let's try BounceInterpolator.

Hey, the effect is pretty good. There are many other system-provided Interpolators. You can try them one by one. We won't go into details here.

Now let's look at:

1) Internal implementation mechanism of Interpolator

Let's look at the source code of the TimeInterpolator interface, and we find that there is only one getInterpolation() method.

Simple explanation: The getInterpolation() method receives an input parameter, which changes as the animation runs, but it changes very regularly, increasing uniformly according to the set animation duration, with a range from 0 to 1. That is, when the animation starts, the value of input is 0, and when the animation ends, the value of input is 1, and the intermediate values change between 0 and 1 as the animation duration changes.

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

Let's look at the code in LinearInterpolator:

Here, the input value is returned directly without any processing, that is, the fraction value is equal to the input value, which is the implementation method of the uniform motion Interpolator. The algorithm is different, which involves some mathematics, and I feel the importance of mathematics again. Let's post the source code of BounceInterpolator here:

Don't ask me about the algorithm here; I don't know either. Let's look at an easier one: AccelerateDecelerateInterpolator.

This Interpolator has an effect of accelerating first and then decelerating: (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f. The understanding of the algorithm:

Solution: Since the range of input is [0,1], the range of values in cos is [π,2π], corresponding to -1 and 1; after dividing this value by 2 and adding 0.5, the final return value of the getInterpolation() method is still in the range [0,1], and the corresponding curve is as follows:

So it's an acceleration first and then deceleration process.

Well, I can't play as a dunce anymore...

2) Custom Interpolator

Okay, let's not be sad for now, let's write a custom Interpolator example first: It's very simple, implement the TimeInterpolator interface, and override the getInterpolation method.

Sample code:

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);
        }
    }
}

Call setInterpolator(new DecelerateAccelerateInterpolator()) to set it. Due to space limitations, no images are posted.


3. ViewPropertyAnimator

Added a new feature to the system since 3.1, providing a more convenient way to operate View animations. If it was before, to make a TextView change from normal state to transparent state, it would be written like this:

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

With ViewPropertyAnimator, it becomes more understandable:

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

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

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

The usage is simple, just check the documentation when using it. Also, there are a few detailed points to pay attention to:

All interfaces of ViewPropertyAnimator are designed using chained syntax, where each method returns its own instance. Therefore, after calling one method, you can directly chain another method call, allowing all functionalities to be connected in a single line of code, enabling even complex animations to be achieved with minimal code.


4. Sample Code Download

AnimatorDemo3.zip

A collection of animations can be found on Github, featuring many animation effects. Here is the link:

BaseAnimation Collection

To study how various animations are implemented, you can check the source code yourself.


Summary of This Section

>

In this section, we covered some more advanced topics such as Evaluators, Interpolators, and ViewPropertyAnimator, expanding your knowledge. This section also marks the end of the basic introduction to drawing in Android. If you have mastered the content of this chapter, learning about custom controls or understanding custom controls written by others should no longer be daunting.

Thank you to Guo Shen for his articles, as much of the content on property animations was taken directly from him.

PS: The screenshots were switched to an emulator because my N5 was acting up...

-1.0 Android Basic Introduction Tutorial

-1.0.1 2015 Latest Android Basic Introduction Tutorial Table of Contents

-1.1 Background and System Architecture Analysis

-1.2 Development Environment Setup

-1.2.1 Using Eclipse + ADT + SDK to Develop Android APP

-1.2.2 Using Android Studio to Develop Android APP

-1.3 Solving SDK Update Issues

-1.4 Genymotion Emulator Installation

-1.5.1 Git Tutorial for Basic Local Repository Operations

-1.5.2 Using GitHub to Set Up a Remote Repository

-1.6 How to Use the 9-Patch Image

-1.7 Interface Prototype Design

-1.8 Project Source Analysis (Various Files, Resource Access)

-1.9 Android Program Signing and Packaging

-1.11 Decompiling APK to Obtain Code & Resources

-2.1 Concepts of View and ViewGroup

-2.2.1 LinearLayout (Linear Layout)

-2.2.2 RelativeLayout (Relative Layout)

-2.2.3 TableLayout (Table Layout)

-2.2.4 FrameLayout (Frame Layout)

-2.2.5 GridLayout (Grid Layout)

-2.2.6 AbsoluteLayout (Absolute Layout)

-2.3.1 Detailed Explanation of TextView (Text Box)

-2.3.2 Detailed Explanation of EditText (Input Box)

-2.3.3 Button and ImageButton

-2.3.4 ImageView (Image View)

-2.3.5 RadioButton (Radio Button) & Checkbox (Checkbox)

-2.3.6 ToggleButton and Switch

-2.3.7 ProgressBar (Progress Bar)

-2.3.8 SeekBar (Drag Bar)

-2.3.9 RatingBar (Star Rating Bar)

-2.4.1 ScrollView (Scroll Bar)

-2.4.2 Date & Time Components (Part 1)

-2.4.3 Date & Time Components (Part 2)

-2.4.4 Basic Explanation of Adapter

-2.4.5 Simple Use of ListView

-2.4.6 Optimization of BaseAdapter

-2.4.7 Focus Issues with ListView

-2.4.8 Solving Checkbox Misalignment Issues in ListView

-2.4.9 Data Update Issues with ListView

-2.5.0 Building a Reusable Custom BaseAdapter

-2.5.1 Implementation of Multi-Layout ListView Items

-2.5.2 Basic Use of GridView (Grid View)

-2.5.3 Basic Use of Spinner (List Option Box)

-2.5.4 Basic Use of AutoCompleteTextView (Auto-Complete Text Box)

-2.5.5 Basic Use of ExpandableListView (Collapsible List)

-2.5.6 Basic Use of ViewFlipper (Flip View)

-2.5.7 Basic Use of Toast

-2.5.8 Detailed Explanation of Notification (Status Bar Notification)

-2.5.9 Detailed Explanation of AlertDialog (Dialog Box)

-2.6.0 Basic Use of Other Common Dialogs

-2.6.1 Basic Use of PopupWindow (Floating Box)

-2.6.2 Menu (Menu)

-2.6.3 Simple Use of ViewPager

-2.6.4 Simple Use of DrawerLayout (Official Side Menu)

-3.1.1 Event Handling Mechanism Based on Listeners

-3.2 Event Handling Mechanism Based on Callbacks

-3.3 Analysis of Handler Message Passing Mechanism

-3.4 TouchListener vs OnTouchEvent + Multi-Touch

-3.5 Listening for Content Changes in EditText

-3.6 Responding to System Setting Events (Configuration Class)

-3.7 AsyncTask Asynchronous Task

-3.8 Gestures (Gestures)

-4.1.1 Activity Beginner

-4.1.2 Activity Intermediate

-4.1.3 Activity Advanced

Follow on WeChat

❮ Web Image Optimization Ubuntu Modify Dns ❯