Android animation is owned by Catango

preface

Animation effect has always been a very important part of human-computer interaction. The introduction of animation effect will make the interaction more friendly and make users get a more pleasant experience. As a front-end developer, animation is also a must-have skill.

View Animation

View Animation includes Tween Animation and Frame Animation (Drawable Animation). These are the two kinds of animations before Android 3.0.

The frame of animation

A frame animation, sometimes called a Drawable animation, allows you to perform slideshows. This animation is actually a Drawable, so the XML definition file for this animation is usually in the RES/Drawable/directory. The essence of frame animation is our visual residue.

We usually refer to the animation resource under Drawable, and then call start()/stop() in code to start or stop the animation. We can also create a frame-by-frame animation in Java code, create an AnimationDrawable object, and then call addFrame(Drawable Frame,int Duration) to add frames to the animation. Start () and stop() are then called ~ XML is recommended to define the animation.

Specific labels are:

  • <animation-list>: Must be the root node, which contains multiple nodes< item>Elements. Properties include Android :oneshot true for once, false for loop.
  • < item>:a child of animation-list, containing the following attributes:
    • Android :drawable The drawable resource of a frame.
    • Android :duration Indicates how long a frame is.

So for example, we’re in drawable

< ?xml version="1.0" encoding="utf-8"? > < animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    < item android:drawable="@color/black" android:duration="300"/>
    < item android:drawable="@color/white" android:duration="300"/>
< /animation-list>Copy the code

And then in Kotlin

  img_test.apply {
            setBackgroundResource(R.drawable.test_frame)
            setOnClickListener {
                if ((background as AnimationDrawable).isRunning)
                    (background as AnimationDrawable).stop()
                else (background as AnimationDrawable).start()
            }
        }Copy the code

This will automatically play the resource set in drawable when we click on the image. Note that the Animation’s start method cannot be called in the Activity’s onCreate method because the AnimationDrawable is not fully attached to the Window.

Filling between animation

Tween Animation applies only to View objects and only supports some properties, such as zooming and rotation, but not background color changes. And for the Tween Animation, it doesn’t change the property value, it just changes the position of the View object, it doesn’t change the View object itself, for example, you have a Button, coordinates (100,100), Width:100,Height:100, And you have an animation that moves it (200,200), and you see that the area that triggers the button click during the animation is still (100,100)-(200,200).

Tween animations are defined in XML or Android code, but XML files are recommended because they are more readable and reusable. It is the parent of all tween animation classes:

public abstract class Animation implements CloneableCopy the code

This note is distinguished from the parent class of the property animation.

The Java class name XML keyword Description information
AlphaAnimation Place it in the res/anim/ directory Gradient transparency animation effect
RotateAnimation Place it in the res/anim/ directory Screen transfer rotation animation effect
ScaleAnimation Place it in the res/anim/ directory Tween size scaling animation effect
TranslateAnimation Place it in the res/anim/ directory Screen shift position move animation effect
AnimationSet Place it in the res/anim/ directory A container that holds other animation elements alpha, scale, Translate, rotate, or other set elements

Animation attributes

XML attributes Java method explain
android:detachWallpaper setDetachWallpaper(boolean) Whether to run on wallpaper
android:duration setDuration(long) Animation duration in milliseconds
android:fillAfter setFillAfter(boolean) Control whether the last state of the animation remains when the animation ends
android:fillBefore setFillBefore(boolean) Control whether the animation ends in the state before the animation began
android:fillEnabled setFillEnabled(boolean) The same effect as Android :fillBefore
android:interpolator setInterpolator(Interpolator) Set interpolators (specify animation effects, such as rebound, etc.)
android:repeatCount setRepeatCount(int) Repeat the number
android:repeatMode setRepeatMode(int) The repeat type has two values: Reverse for playback in reverse order and restart for playback from the beginning
android:startOffset setStartOffset(long) The time, in milliseconds, to wait to start running after calling the start function
android:zAdjustment setZAdjustment(int) Represents the position on the Z-axis (top/bottom/normal) where the content is animated when it runs. The default is normal

Alpha attribute

XML attributes Java method explain
android:fromAlpha AlphaAnimation (float fromAlpha,…). Opacity at the beginning of the animation (0.0 to 1.0, 0.0 is fully transparent, 1.0 is opaque)
android:toAlpha AlphaAnimation (… , float toAlpha) Opacity at the end of the animation, ditto

Rotate the attribute

XML attributes Java method explain
android:fromDegrees RotateAnimation (float fromDegrees,…). Rotation Angle, positive represents clockwise degrees, negative represents counterclockwise degrees
android:toDegrees RotateAnimation (… The float toDegrees,…). Rotation end Angle, positive represents clockwise degrees, negative represents counterclockwise degrees
android:pivotX RotateAnimation (… The float pivotX,…). Scale the starting X coordinate (value, percentage, percentage P, for example, 50 means the top left coordinate of the current View plus 50px as the initial point, 50% means the top left corner of the current View plus 50% of the width and height of the current View as the initial point, 50% P means the top left corner of the current View plus 50% of the width and height of the parent control as the initial point)
android:pivotY RotateAnimation (… , float pivotY) Scale the starting Y coordinate, same as above

Scale properties

XML attributes Java method explain
android:fromXScale ScaleAnimation (float fromX,…). Initial X-axis scaling, 1.0 means no change
android:toXScale ScaleAnimation (… , float toX,…). End X-axis scaling
android:fromYScale ScaleAnimation (… The float fromY,…). Initial Y scale
android:toYScale ScaleAnimation (… The float toY,…). End Y axis scaling
android:pivotX ScaleAnimation (… The float pivotX,…). Scale the starting X-axis coordinates (value, percentage, percentage P, for example, 50 means the top left coordinate of the current View plus 50px as the initial point, 50% means the top left corner of the current View plus 50% of the width and height of the current View as the initial point, 50% P means the top left corner of the current View plus 50% of the width and height of the parent control as the initial point)
android:pivotY ScaleAnimation (… , float pivotY) Scale the Y coordinates of the starting point, as above

Detailed explanation of the Translate attribute

XML attributes Java method explain
android:fromXDelta TranslateAnimation (float fromXDelta,…). X-axis coordinates of the starting point (value, percentage, percentage P, for example, 50 means the starting point with the coordinate of the upper left corner of the current View plus 50px; 50% means the starting point with the upper left corner of the current View plus 50% of the width and height of the current View; 50% P means the starting point with the upper left corner of the current View plus 50% of the width and height of the parent control)
android:fromYDelta TranslateAnimation (… , float fromYDelta,…). Same rule as above
android:toXDelta TranslateAnimation (… , float toXDelta,…). The x-coordinate of the end point is the same as above
android:toYDelta TranslateAnimation (… , float toYDelta) The y-coordinate of the end point is the same as above

interpolator

Interpolator Interpolator is used to control the change rate of an animation. We can Interpolator interface ourselves to control the change rate of an animation. Android has five Interpolator classes available:

  • LinearInterpolator: The animation changes at a uniform speed
  • AccelerateInterpolator: Changes slowly at the beginning of an animation, then begins to accelerate
  • AccelerateDecelerateInterpolator: at the beginning of the animation, the end of the local change slower, middle speed
  • CycleInterpolator: Animation is looped a specific number of times at a sinusoidal speed: math.sin (2 mCycles Math.PI * input)
  • Activity: Change fast at the beginning of the animation, then slow down
  • AnticipateInterpolator: reverse, making a paragraph change in the opposite direction before accelerating playback
  • AnticipateOvershootInterpolator: at the start of the backward and forward to jilt a certain value returns the value of the final
  • BounceInterpolator: jumps. A value will jump when approaching a destination value, such as the destination value 100. Subsequent values may be 85,77,70,80,90,100
  • OvershottInterpolator: interpolates back, eventually exceeding the target value and then slowly changing to the target value

Introduction to Use:

Above these are some XML and Java methods of tween animation introduction, these method attributes do not remember it does not matter, we can view at any time, the most important or how to use. In fact, the usage is also very simple, very routine, we just need to remember the routine can. Let’s take a simple example of rotating animation.

The first is the XML

< ?xml version="1.0" encoding="utf-8"? > < rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:duration="1000"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="infinite"
    />Copy the code

Animation activity @ Android: Animaccelerate_theme ator is the interpolator that will change at the beginning of the animation and then slow down.

After writing the XML, in the Java code

    Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_rotate);
    testImg.setAnimation(animation);
    animation.start();
    animation.cancel();Copy the code

We can see that we first create an Animation object and then load the Animation defined in the XML into the Animation object using the loadAnimation method of AnimationUtils. We then pass in the animation via the View setAnimation method, which binds the animation to the View. Finally, the animation is started or cancelled using the animation’s start and cancel methods. We can set the listener for the animation.

Property Animation

Android 3.0 introduced property animation, property animation can easily achieve a lot of View animation can not do. In fact, remember a point on the line, the principle of property animation is to modify the control of the property value of the animation. Of course, the price of power is complexity to use.

All the parent classes of the property animation are it:

public abstract class Animator implements CloneableCopy the code

This note is distinguished from the tween animation.

Here are the related apis:

  • The Animator creates the base class for property animations, usually using two of its subclasses rather than directly
  • ValueAnimator The direct derived class of an Animator. It uses a time-loop mechanism to calculate the animation transition between values. We only need to provide the initial value and the end value to the class, and tell the length of time required for the animation, and the class will automatically help us smooth the transition from the initial value to the end. This class also manages playback times, modes, listeners, and so on.
  • AnimatorSet A direct derivative of an Animator that can combine multiple animators and specify the order in which the animators are played.
  • ObjectAnimator, a subclass of ValueAnimator, allows us to animate properties of specified objects.
  • Evaluator calculator, which tells the animation system how to transition from initial to final values. The following evaluators are available:
    • IntEvaluator: Used to calculate an int attribute
    • FloatEvaluator: Used to evaluate float properties
    • ArgbEvaluator: calculator used to calculate the value of a hexadecimal representation color
    • TypeEvaluator: A public interface for the computation classes described above. You can customize the interface yourself.

ValueAnimator

Use process:

  1. Call ValueAnimator’s ofInt(), ofFloat(), or ofObject() static methods to create a ValueAnimator instance
  2. Call the setXxx method of the instance to set the animation duration, interpolation method, repetition number, etc
  3. Call the instance’s addUpdateListener to add the AnimatorUpdateListener listener. In this listener, you can get ValueAnimator values that you can apply to the specified object
  4. Call the instance’s start() method to start the animation! We can also see that both ofInt and ofFloat have a float/int… Values stand for multiple values!

Here’s an example:

// Move according to the trajectory equationlineAnimator() {
        width = ly_root.getWidth();
        height = ly_root.getHeight();
        ValueAnimator xValue = ValueAnimator.ofInt(height,0,height / 4,height / 2,height / 4 * 3 ,height);
        xValue.setDuration(3000L);
        xValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@override public void onAnimationUpdate(ValueAnimator animation) { animation.getAnimatedValue(); int x = width / 2; moveView(img_babi, x, y); }}); xValue.setInterpolator(new LinearInterpolator()); xValue.start(); } private void moveView(View view, int rawX, int rawY) { int left = rawX - img_babi.getWidth() / 2; int top = rawY - img_babi.getHeight(); int width = left + view.getWidth(); int height = top + view.getHeight(); view.layout(left, top, width, height); }Copy the code

The moveView method rearranges the View, the value of xValue can be seen from the argument list, and then sets the listener for each update. In this listener, moveView method is called each time to change the View layout. For composite animation, we could do this:

// Zoom effect private voidscaleAnimator(){

        final floatScale = 0.5 f; AnimatorSet scaleSet = new AnimatorSet(); ValueAnimatorSmall = ValueAnimator.offloat (1.0f, scale); valueAnimatorSmall.setDuration(500); ValueAnimatorLarge = Valueanimator.offloat (scale, 1.0f); valueAnimatorLarge.setDuration(500); valueAnimatorSmall.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                floatscale = (Float) animation.getAnimatedValue(); img_babi.setScaleX(scale); img_babi.setScaleY(scale); }}); valueAnimatorLarge.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                floatscale = (Float) animation.getAnimatedValue(); img_babi.setScaleX(scale); img_babi.setScaleY(scale); }}); scaleSet.play(valueAnimatorLarge).after(valueAnimatorSmall); scaleSet.start(); }Copy the code

For this composite animation, we can set the animation instance with play After, and then the animation executes the play animation and then the after instance. Of course, there is a similar method called with, where the two animations will play together.

  • After (Animator anim) inserts the existing animation after the incoming animation
  • After (long delay) Executes the existing animation after the specified millisecond delay
  • Before (Animator anim) inserts an existing animation before the incoming animation
  • With (Animator anim) executes an existing animation and an incoming animation simultaneously

ObjectAnimator

ObjectAnimator is probably the most commonly encountered class compared to ValueAnimator, because ValueAnimator does nothing more than a smooth animation transition to a value, but we don’t really use this feature in many situations. ObjectAnimator, on the other hand, can animate any property of any object directly, such as the Alpha property of a View. ObjectAnimator is not designed for a View, but for any object.

Since ObjectAnimator inherits from ValueAnimator, its usage should be similar to ValueAnimator.

 ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f);Copy the code

ObjectAnimator will help us change the alpha property of our TextView object from 1F to 0F. The TextView object then needs to constantly refresh the display of the interface based on changes in the alpha property value, so that the user can see how the animation fades in and out.

So does the textView object have an alpha property? No, not only does TextView not have this property, but all of its parent classes don’t have this property either! Textview does not have an alpha property, so how does ObjectAnimator operate? ObjectAnimator does not directly operate on the property name we pass in. Instead, ObjectAnimator looks for the get and set methods that correspond to the property name.

public void setAlpha(float value);  
public float getAlpha();Copy the code

ObjectAnimator is much easier to use than ValueAnimator, we only need to instantiate it, other uses are the same as ValueAnimator.

Monitor for animation

AnimatorUpdateListener is the listener for ValueAnimator. It calls onAnimationUpdate when the value state changes. In addition to these events: AnimatorListener, we can call the addListener method to add listeners, and then override the following four callback methods:

  • OnAnimationStart () : Animation starts
  • OnAnimationRepeat () : Animation is repeated
  • OnAnimationEnd () : Animation ends
  • OnAnimationCancel () : Animation cancelled

To add an AnimatorListener, you’ll need to override all four methods, which is a hassle to write, but Android already provides an adapter class: AnimatorListenerAdapter, which already implements every interface method, so we can just write one callback method here.

Evaluator

We use static methods ofInt,ofFloat, and ofObject to create instances of ValueAnimator when we invoke property animations. In this example, we use ofInt,ofFloat. ValueAnimator also has an ofObject method to construct ValueAnimator instances. What does this do?


    public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
        ValueAnimator anim = new ValueAnimator();
        anim.setObjectValues(values);
        anim.setEvaluator(evaluator);
        return anim;
    }Copy the code

Let’s poke in and look at the source parameters. The first parameter is something called TypeEvaluator, which is the calculator that tells the animation system how to transition from an initial value to an end value. As mentioned earlier, TypeEvaluator is the base class for all evaluators. Again, the system provides the following types of evaluators:

  • IntEvaluator: Used to calculate an int attribute
  • FloatEvaluator: Used to evaluate float properties
  • ArgbEvaluator: calculator used to calculate the value of a hexadecimal representation color
  • TypeEvaluator: A public interface for the computation classes described above. You can customize the interface yourself.

Of course, these evaluators are TypeEvaluator implementations. Let’s start with what the TypeEvaluator interface looks like:

public interface TypeEvaluator<T> {
    public T evaluate(float fraction, T startValue, T endValue);

}Copy the code

This is the evaluate method, simple? The meanings of the three parameters are as follows:

  • Fraction: The completion of the animation. We use this to calculate the value of the animation
  • StartValue: indicates the startValue of the animation
  • EndValue: endValue of the animation

TypeEvaluator is an interface that implements TypeEvaluator. IntEvaluator implements TypeEvaluator.

public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return(int)(startInt + fraction * (endValue - startInt)); }}Copy the code

The TypeEvaluator interface is implemented and the Evaluate method is overridden, which returns the value of the animation. What is the value of the animation? IntEvaluator returns the value of the animation = initial + completion * (End – initial) so that when completion is 100%, the value of the animation is the end value. As you’ll notice, the TypeEvaluator is passing in a generic type, which we’ll define as Object.

Now let’s take the example of a custom Evaluator.

package com.example.yang.testkotlin.widget; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; /** * @author YangCihang * @since 17/10/18. * email [email protected] */ public class CircleAnimView extends View { public static final int RADIUS = 80; private Point currentPoint; private Paint mPaint; private int mColor; // We must write the get and the attributesetPublic CircleAnimView(Context Context) {super(Context); } public CircleAnimView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public CircleAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private voidinit() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }

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

    private void drawCircle(Canvas canvas) {
        float x = currentPoint.x;
        floaty = currentPoint.y; DrawCircle (x, y, RADIUS, mPaint); drawCircle(x, y, RADIUS, mPaint); } private voidstartAnimation() {
        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); AnimatorSet AnimatorSet = new AnimatorSet(); animatorSet.play(anim).with(objectAnimator); animatorSet.setStartDelay(1000L); animatorSet.setDuration(3000L); animatorSet.start(); } / / PointEvaluator implements TypeEvaluator<Point> {@override public Point evaluate(floatfraction, Point startValue, Point endValue) {// endValue + endValue * (endValue. X + startValue. X); int y = (int) (startValue.y + fraction * (endValue.y - startValue.y));returnnew Point(x, y); Public implements TypeEvaluator<Integer> {public implements TypeEvaluator<Integer>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)));
            returnColor.argb(alpha, red, green, blue); }} //color get andsetMethod ~ public intgetColor() {
        return mColor;
    }

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

Here we define two Evaluator classes to represent coordinate changes and color changes respectively. Note that when we want to change the color property, we must write setColor and getColor methods, for the reasons explained above.

Interpolator

Interpolator is called Interpolator or Interpolator. In tween animation we introduced a few common interpolators that we can go back to. Both tween animation and property animation can use interpolators. Interpolator interface is Interpolator interface. Interpolator interface is Interpolator interface. Interpolator interface is Interpolator interface. This makes all past Interpolator implementation classes Interpolator can be used directly in a property animation! We can set different interpolators by calling the setInterpolator() method of an animation object. Such as:

animatorSet.setInterpolator(new AccelerateInterpolator(2f))Copy the code

The values in parentheses are used to control the acceleration.

Custom Interpolator

Interpolator is Interpolator; Interpolator is Interpolator; Interpolator is Interpolator; Interpolator is Interpolator; Interpolator is Interpolator.


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); }}}Copy the code

But if we’re going to do some complicated rate changes, we’re going to need some math.