preface

  • The use of animation isAndroidKnowledge commonly used in development
  • This article will introduce it in detailAndroidIn the animationAttribute animationPrinciple & use of


directory


1. The reason for the appearance of the property animation

  • Property animation (Property Animation) is theThe Android 3.0(API 11) after a new animation mode is provided
  • So why provide property animation (Property Animation)?

1.1 background

Implementing animations is very common in Android development, so the Android system provides two ways to implement animations from the beginning:

  • Frame by frame animation (Frame Animation)
  • Tween animation (Tweened animation

1.2 the problem

Frame-by-frame animation and tween animation have certain disadvantages:

A. Scope limitations: View

That is, tween animation can only work on the View, that is, you can only animate a Button, TextView, or even a LinearLayout, or other components inherited from the View, but you can’t animate non-View objects

  1. In some cases the animation is just a property of the view & object rather than the whole view;
  2. For example, if you want a view’s color to change dynamically, you need to animate the view’s color properties instead of animating the entire view
B. Do not change the properties of the View, just change the visual effect
  • The tween animation just changedViewWithout really changing itViewProperties.
  • For example, move the button in the upper-left corner of the screen to the lower-right corner of the screen through the tween animation
  • Clicking on the current position of the button (bottom right corner of the screen) has no effect, because the button is still in the top left corner of the screen. The tween animation just draws the button to the bottom right corner of the screen, changing the visual effect.
C. Single animation effect
  • Tween animation can only achieve translation, rotation, zoom and transparency of these simple animation requirements
  • Once you encounter relatively complex animation effects, that is, beyond the above four animation effects, then tween animation cannot be achieved.

That is, there are great limitations in functionality & scalability

1.3 the problem

  • In order to solve the defects of tween animation, inThe Android 3.0(API 11) To begin with, the system provides a new animation mode: property animation (Property Animation)
  • Next, I’ll cover property animation (Property Animation)

2. Introduction

  • Object: AnyJavaobject

No longer limited to View View objects

  • Animation effect: can customize various animation effects

No longer limited to the four basic transformations: translation, rotation, scale & transparency


Characteristics of 3.

  • Scope objects are extended: not just View objects, but even no objects
  • Animation effects: Not just the 4 basic transformations, but other animation effects
  • Field of action: introduced after API11

4. Working principle

  • In a certain time interval, the object is animated on the property by constantly changing the value and constantly assigning the value to the property of the object

It can be any property of any object

  • The specific working principle is as follows:

  • From how this works, you can see that property animation has two very important classes:ValueAnimatorClass &ObjectAnimator
  • In fact, the use of property animation basically depends on these two classes
  • So, I’ll focus on these two classes when I introduce the specific use of property animation below.

5. Specific use

5.1 ValueAnimator class

  • Definition: a core class in the property animation mechanism
  • The principle of animation: through constant control value changes, and then constantly manually assigned to the attributes of the object, so as to achieve the animation effect. As shown in figure:

The ValueAnimator class has three important methods:

  1. Valueanimator. ofInt (int values)
  2. Valueanimator.offloat (float values)
  3. Valueanimator. ofObject (int values)

I’ll go through them one by one.

5.1.1 ValueAnimator.ofInt (int values)

  • Function: Transitions an initial value to an end value as an integer value

That is, the valuator is an integer valuator – IntEvaluator

  • Working principle:

  • Specific use:

Special note:

  1. Since ValueAnimator is essentially a value manipulation mechanism, the following introduction first shows how to change a value. (The following example shows how to smoothly transition a value from 0 to 3.)
  2. As for how to animate, the developer needs to manually assign these values to the property values of the object. This will be explained in the next section.

The value can be set using XML or Java code. Setting Method 1: Set using Java code

In practical development, it is recommended to animate properties in Java code: because many times the starting value of a property cannot be determined in advance (it cannot be set using XML), it needs to be obtained dynamically in Java code.

ValueAnimator anim = ValueAnimator.ofint (0, 3); valueAnimator.ofint (0, 3); // ofInt () has two functions // 1. Will be introduced to the multiple parameters of smooth transition: Int here introduced into 0 s and 1 s, said he would value the smooth transition from 0 to 1 / / if the incoming 3 Int a, b, c, is from a smooth transition to b first, then smooth transition from b to c, // Valueanimator.ofint () is built with an integer valuator and uses the default. // Let's look at the source analysis of ofInt() ->> Focus 1 // Step 2: Set the playback properties of the animation to anim.setDuration(500); // Set the animation running time anim.setstartDelay (500); // Set the animation delay to anim.setrepeatCount (0); Anim.setrepeatmode (valueanimator.restart); // Set animation playback times = playback times +1 // Animation playback times = infinite; Valueanimator. RESTART(default): playback in positive order // valueanimator. REVERSE: playback in REVERSE order // Step 3: Manually assign the changed value to the property value of the object: Anim. addUpdateListener(new ValueAnimator)AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int currentValue = (Integer) animation.getAnimatedValue(); // Get the changed value system.out.println (currentValue); // Print the changed value // Step 4: Assign the changed value to the property value of the object, as detailed below: view.setProperty (currentValue); // Step 5: Refresh the View, that is, redraw it to animate view.requestLayout (); }}); anim.start(); Public static ValueAnimator ofInt() public static ValueAnimator ofInt(int... Values) {// Allow one or more Int arguments to be passed // 1. Input a case (such as a) : from 0 to A; Anim = new ValueAnimator(); anim = new ValueAnimator(); anim = new ValueAnimator(); // Create the animation object anim.setintValues (values); // Assign the value passed to the animation objectreturn anim;
    }
Copy the code

rendering

The transition from an initial value to an end value is as follows:

** Set method 2: Make XML code ** reusable, so that common animations are written to XML and can be reused across interfaces

  • Step 1: In the pathres/animatorCreate the corresponding animation in the folder.xmlfile

Set this to res/animator/set_animation.xml

  • Step 2: Set the animation parameters

set_animation.xml

// ValueAnimator uses the <animator> tag <animator XMLNS: Android ="http://schemas.android.com/apk/res/android"  
    android:valueFrom="0"// Initial android:valueTo="100"// End Value Android :valueType="intType"// Change value type:floatType & intType

    android:duration="3000"// Animation duration (ms), must be set for animation to be effective android:startOffset ="1000"// Animation delay start time (ms) Android :fillBefore ="true"// Whether the view stays in the state where the animation started after the animation is played. The default istrueAndroid: fillAfter ="false"// Whether the view will stay at the end of the animation state after the animation has finished, taking precedence over fillBefore. The default value is fillBeforefalseAndroid: fillEnabled ="true"// Whether to apply the fillBefore value has no effect on the fillAfter value. The default value istrueRepeatMode = "restart" android:repeatMode= "restart" Defaults to restart | android: repeatCount = "0" / / replay number (so the animation plays = replay number + 1), Interpolator = @[package:] Anim /interpolator_resource // Interpolator, which affects the playback speed of animation, will be discussed in detail below.Copy the code
  • Step 3: Start the animation in Java code
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.set_animation); // Load animator.settarget (view); // Set animator.start(); // Start animationCopy the code

rendering

The effect is the same as the first way.

Example is given to illustrate

  • Next, I’ll combine this with the manual assignment of object attributes to achieve a complete animation
  • Achieved animation effect: button width from150pxZoom in to the500px
Button mButton = (Button) findViewById(R.id.Button); // Create the animation object: Button as an example // Step 1: ValueAnimator ValueAnimator = ValueAnimator.ofint (mbutton.getLayOutParams ().width, 500); // Start value = current button width, which is set to 150 in the XML file // end value = 500 // Valueanimator.ofint () has built-in integer valuator, which is used by default. Do not need to set up / / how the default Settings the transition from the initial value of 150 to 500 the end value / / step 2: set play all kinds of properties of the animation. ValueAnimator setDuration (2000); / / set the animation to run length: 1 s / / step 3: the attribute value manually assigned to the object's properties: here is to assign values to the width of the button / / set the update listener: namely the numerical change every time will invoke the update method. ValueAnimator addUpdateListener (newAnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animator) { int currentValue = (Integer) animator.getAnimatedValue(); System.out.println(currentValue); Mbutton.getlayoutparams ().width = currentValue; Mbutton.requestlayout (); mbutton.requestLayout (); mbutton.requestLayout (); }}); valueAnimator.start(); // Start animation}Copy the code

rendering

5.1.2 Valueanimator. oFloat (float values)

  • Function: Transitions an initial value to an end value as a floating-point value

  • Working principle:

  • Specific use: XML Settings/Java code Settings

** Setting method 1: Set ** in Java code

ValueAnimator anim = ValueAnimator.ofFloat(0, 3); OfInt (int values), which is not described hereCopy the code

** Set method 2: Set ** in the XML code

  • Step 1: In the pathres/animatorCreate the corresponding animation in the folder.xmlfile

Set this to res/animator/set_animation.xml

  • Step 2: Set the animation parameters

set_animation.xml

// ValueAnimator uses the <animator> tag <animator XMLNS: Android ="http://schemas.android.com/apk/res/android"// Set the property as above android:valueFrom="0"  
    android:valueTo="100"  
    android:valueType="intType"/>  
Copy the code
  • Step 3: Start the animation in Java code
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.set_animation); // Load animator.settarget (view); // Set animator.start(); // Start animationCopy the code

rendering

As you can see, valueanimator.ofint () differs from valueanimator.ofloat () only on the valuator :(i.e., how to transition from initial to end values)

  • ValueAnimator. OFloat ()Use the default floating-point estimator (FloatEvaluator)
  • ValueAnimator. OfInt ()Use the default integer estimator (IntEvaluator)

The use of valueanimator.ofloat () is not described here.


5.1.3 ValueAnimator. OfObject ()

  • Function: ** transitions the initial value as an object to the end value **

That is, by manipulating objects to achieve animation effects

  • Working principle:

  • Specific use:
MyObject object1 = new myObject(); myObject object2 = new myObject(); ValueAnimator anim = ValueAnimator.ofObject(new myObjectEvaluator(), object1, object2); // Create animation object & set parameters // Parameter description // Parameter 1: custom evaluator object (TypeEvaluator type parameter) - more on this below // Parameter 2: object for initial animation // Parameter 3: End animating object anim.setDuration(5000); anim.start();Copy the code

Before moving on to the use of valueanimator.ofObject (), I’ll talk about TypeEvaluator.

An introduction to TypeEvaluator

  • Effect: Sets the logic of how the animation transitions from the initial value to the end value
  1. Interpolation (Interpolator) determine the change mode of value (uniform speed, accelerated blabla)
  2. Valuation (TypeEvaluator) determines the specific change in value

As you can see from Section 5.1.2:

  • ValueAnimator. OfFloat ()** float from the initial value to the end value **.
  • It’s actually built into the systemFloatEvaluatorValuator, internal realization of the initial value and the end value to floating point type of transition logic
  • Let’s seeFloatEvaluatorCode implementation:
Public class FloatEvaluator implements TypeEvaluator {// Evaluate () public Object implements TypeEvaluator  evaluate(floatFraction, Object startValue, Object endValue) {// Parameter Description // Fraction: indicates the animation completion degree (from which to calculate the current animation value) // startValue, endValue: The start and end values of the animationfloat startFloat = ((Number) startValue).floatValue();  
        
        returnstartFloat + fraction * (((Number) endValue).floatValue() - startFloat); // 1. Subtract the initial value from the end value and calculate the difference between them // 2. Multiply the difference by the fraction coefficient // 3. Add the initial value to get the value of the current animation}}Copy the code
  • ValueAnimator. OfInt () & ValueAnimator. OfFloat ()Both have built-in estimators, i.eFloatEvaluator & IntEvaluator

That is, the system has implemented the logic of how to transition from the initial value to the end value by default

  • But for theValueAnimator. OfObject ()From the above working principle, it can be seen that there is no default implementation of the system, because the animation operation of the object is complex and diverse, the system cannot know how to transition from the initial object to the end object
  • Therefore, forValueAnimator. OfObject (), we need to customize the estimator (TypeEvaluator) to tell the system how to proceed from the initial object to the end object logic
  • The logic of the custom implementation is as follows
Public class ObjectEvaluator implements TypeEvaluator{// Implements evaluate (); // Implements evaluate () @Override public Object evaluate(floatFraction, Object startValue, Object endValue) {// Parameter Description // Fraction: indicates the animation completion degree (from which to calculate the current animation value) // startValue, endValue: The start and end values of the animation... // Write the logic of the object's animation transitionreturnvalue; // Return the logical value of the animation transition}Copy the code

Example is given to illustrate

  • How can I customize the TypeEvaluator interface and animate it with ValueAnimator.ofObject ()

  • Animation effect: a circle moves from one point to another

  • The project directory files are as follows:

Step 1: Define the object class

  • becauseValueAnimator. OfObject ()Is object oriented operation, so you need to customize the object class.
  • In this example, the object to operate on isThe point coordinates of the circle Point.java
Public class Point {// Sets two variables to record the position of the coordinates privatefloat x;
    private floaty; // The constructor is used to set the coordinates.float x, floaty) { this.x = x; this.y = y; } // Get is used to get the coordinate publicfloat getX() {
        return x;
    }

    public float getY() {
        returny; }}Copy the code

Step 2: Implement the TypeEvaluator interface as required

  • implementationTypeEvaluatorThe purpose of the interface is to customize how to transition from the initial point coordinates to the end point coordinates;
  • This example implements a coordinate transition logic from the upper left corner to the lower right corner.

PointEvaluator.java

Public class PointEvaluator implements TypeEvaluator {// evaluate () @Override public Object evaluate(floatfraction, Object startValue, Point startPoint = (Point) startValue; Point endPoint = (Point) endValue; // Calculate the x and y values of the current animation according to the fractionfloat x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
        floaty = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY()); // Encapsulate the calculated coordinates into a new Point object and return Point Point = new Point(x, y);returnpoint; }}Copy the code
  • The above steps are customized according to requirementsTypeEvaluatorThe implementation of the
  • Here’s how to get throughPointObject for animation operations, so as to achieve the entire custom View animation effect.

Step 3: Animate the properties into the custom View

MyView.java

/** * Created by Carson_Ho on 17/4/18. */ public MyView extends View {public static finalfloatRADIUS = 70f; // Circle radius = 70 private Point currentPoint; Private Paint mPaint; Public MyView(Context Context, AttributeSet attrs) {super(Context, attrs); // Initialize the paintbrush mPaint = new Paint(paint.anti_alias_flag); mPaint.setColor(Color.BLUE); } // Draw a circle at the initial point, by listening for the change of the current coordinate value (currentPoint), call onDraw() to redraw the circle, so as to achieve the translation effect @override protected Void onDraw(Canvas Canvas) {// If the current point is empty (i.e. the first time)if(currentPoint == null) { currentPoint = new Point(RADIUS, RADIUS); // Create a point object (the coordinates are (70,70)) // Draw a circle at that point: center = (70,70), radius = 70float x = currentPoint.getX();
            floaty = currentPoint.getY(); canvas.drawCircle(x, y, RADIUS, mPaint); StartPoint = new Point(RADIUS, RADIUS); startPoint = new Point(RADIUS); // Point endPoint = new Point(700, 1000); ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint); // Parameter 1: TypeEvaluator type parameter - using a custom PointEvaluator(which implements the TypeEvaluator interface) // Parameter 2: object point to start the animation // Parameter 3: object point to end the animation // Step 3: Set the animation parameter im.setDuration(5000); // Set the animation duration // Step 3: Through the value update listener, Anim.addupdatelistener (new); anim.addupDatelistener (new); anim.addupDatelistener (new); anim.addupDatelistener (new)  ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { currentPoint = (Point) animation.getAnimatedValue(); // Change the value of the PointEvaluator evaluate () to the current value (currentPoint) // Update the current value (currentPoint) Redraw after each assignment to implement the animation invalidate(); // Invalidate () will refresh the View, i.e. onDraw() will be called again, so onDraw() will be called once every time the coordinate value changes; anim.start(); // Start animation}else// Draw a circle at this point: center = (30,30), radius = 30float x = currentPoint.getX();
            floaty = currentPoint.getY(); canvas.drawCircle(x, y, RADIUS, mPaint); }}}Copy the code

Step 4: Add custom View space to the layout file

activity_main.xml

<? xml version="1.0" encoding="utf-8"? > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="scut.carson_ho.valueanimator_ofobject.MainActivity">

    <scut.carson_ho.valueanimator_ofobject.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
         />
</RelativeLayout>
Copy the code

Step 5: Set up the display view in the main code file

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); }}Copy the code

rendering

The source address

Carson_Ho’s Github address: github.com/Carson-Ho/P…

Pay special attention to

Valueanimator.ofobject () operates on multiple values at the same time by encapsulating multiple values into an object

As in the above example, the essence of the operation is to manipulate the x and y coordinates, but it is encapsulated in a Point object to facilitate the operation of both x and y values at the same time


  • So far, the most important thing about property animationValueAnimatorClass has been explained
  • I’ll move on to another important class:ObjectAnimatorclass

5.2 ObjectAnimator class

5.2.1 Principles of animation

Change the property value of the object directly, so as to achieve the animation effect

  1. Such as direct changeViewthealphaProperty to animate transparency
  2. Inherited fromValueAnimatorClass, the underlying animation implementation mechanism is based onValueAnimatorclass
  • Essential principle: by constantly controlling the change of value, and then constantly automatically assigned to the attributes of the object, so as to achieve the animation effect. The diagram below:

ObjectAnimator: ValueAnimator: ValueAnimator: ObjectAnimator: ValueAnimator

  • ValueAnimatorThe class changes the value first, and thenManual assignmentTo animate objects with properties; isindirectPerform operations on object properties;
  • ObjectAnimatorThe class changes the value first, and thenAutomatic assignmentTo animate objects with properties; isdirectlyPerform operations on object properties;

How to automatically assign attributes to objects is explained below

5.2.2 Specific Use

Since we inherit from the ValueAnimator class, we use a very similar method: XML Settings/Java Settings

Setting Mode 1:JavaSet up the

ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float. values); // 1. Create an animation instance // 2. Parameter Settings: The parameters are described as follows: // Object Object: the Object to be operated // String Property: the property of the Object to be operated //float. Values: // If there are two parameters a,b, then the animation effect is from the a value of the property to the B value // If there are three parameters A,b,c, then the animation effect is from the A value of the property to the B value to the C value // and so on // How to transition from the initial value to the end value, Here objectAnimator.offloat () is a built-in FloatEvaluator, anim.setDuration(500); // Set the animation running time anim.setstartDelay (500); // Set the animation delay to anim.setrepeatCount (0); Anim.setrepeatmode (valueanimator.restart); // Set animation playback times = playback times +1 // Animation playback times = infinite; // Valueanimator. RESTART(default): playback in positive order // valueanimator. REVERSE: playback in REVERSE animator.start(); // Start animationCopy the code

** Set method 2: Set ** in the XML code

  • Step 1: In the pathres/animatorCreate animation effects in the folder.xmlfile

Set this to res/animator/set_animation.xml

  • Step 2: Set the animation parameters

set_animation.xml

// ObjectAnimator uses the <animator> tag < ObjectAnimator XMLNS: Android ="http://schemas.android.com/apk/res/android"  
    android:valueFrom="1"// Initial android:valueTo="0"// End Value Android :valueType="floatType"// Change value type:floatType & intType
    android:propertyName="alpha"// Attribute name of object change />Copy the code

Start the animation in Java code

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.view_animation); // Load animator.settarget (view); // Set animator.start(); // Start animationCopy the code
  • Here are four basic transformations: pan, rotate, scale, and transparency

A. transparency

mButton = (Button) findViewById(R.id.Button); ObjectAnimator animator = objectAnimator. ofFloat(mButton, ObjectAnimator)"alpha", 1f, 0f, 1f); // Animating object is mButton // Animating object is transparency alpha // Animating effect is: normal - transparent - normal animator.setDuration(5000); animator.start();Copy the code

B. rotating

mButton = (Button) findViewById(R.id.Button); ObjectAnimator animator = objectAnimator. ofFloat(mButton, ObjectAnimator)"rotation", 0f, 360f); // Animator.setDuration (5000); // Animator.setDuration (5000); animator.start();Copy the code

C. translation

mButton = (Button) findViewById(R.id.Button); // Create an animation object: Use Button as an examplefloatcurTranslationX = mButton.getTranslationX(); ObjectAnimator animator = objectAnimator. ofFloat(mButton, ObjectAnimator)"translationX", curTranslationX, 300,curTranslationX); // The animating object is mButton. // The animating object is panned on the X-axis"translationY"// Move from current position to x=1500 and then to initial position animator.setDuration(5000); animator.start();Copy the code

D. the zoom

mButton = (Button) findViewById(R.id.Button); ObjectAnimator animator = objectAnimator. ofFloat(mButton, ObjectAnimator)"scaleX", 1f, 3f, 1f); Animator.setduration (5000); // Animator.setDuration (5000); // Animator.setDuration (5000); animator.start();Copy the code


  • In the above tutorial, we used the four basic animation effects of property animation: transparency, pan, rotate and scale

The second String property argument in ObjectAnimator.offloat () is passed blabLa alpha, rotation, translationX, and scaleY

attribute role Numeric types
Alpha Controls the transparency of the View float
TranslationX Control the displacement in the X direction float
TranslationY Control the Y displacement float
ScaleX Controls the X scaling factor float
ScaleY Controls the scaling factor in the Y direction float
Rotation Controls the degree of rotation along the screen direction float
RotationX Controls the degree of rotation along the X axis float
RotationY Controls the degree of rotation along the Y-axis float

Question: What other attribute values can be passed in as the second argument to ofFloat()? Answer: Any property value. Because:

  • ObjectAnimatorThe essence of class to achieve animation effect by changing the object property value is: by constantly controlling the change of value, and then constantly automatically assign to the object property, so as to achieve animation effect

  • The nature of automatically assigning attributes to an object is to call the set () & get () methods of that object’s attribute
  • So,ObjectAnimator.ofFloat(Object object, String property, float .... values)The second argument to is passed to letObjectAnimatorClass to find the property name of the object based on the property name passed inSet () & get ()Method to assign the value of an object property, as in the example above:
ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "rotation", 0f, 360f); // The ObjectAnimator does not operate directly on the name of the property we passed in, but on the value of the property we passed in"rotation"Find the get and the property name of the objectsetMethod, thus throughset() &get () assigns the property // Because the Button object has the rotation property corresponding to get &setThe rotation property passed in by the // method is valid, so the rotation property can be operated on and assigned to public voidsetRotation(float value);  
public floatgetRotation(); // In fact, these two methods are provided by the View object, so any object that inherits from the View will have this propertyCopy the code

As for how to do automatic assignment, let’s go straight to the source code analysis:

ObjectAnimator animator = ObjectAnimator. OfFloat (Object Object, String property,float. values); anim.setDuration(500); animator.start(); <-- start() --> @override public void Overridestart() {  
    AnimationHandler handler = sAnimationHandler.get();  

    if(handler ! = null) {/ / judgment for animation (Pending) whether there is the same as the current animation in animation, if you have the same animation to cancel numAnims = handler. MPendingAnimations. The size ();for (int i = numAnims - 1; i >= 0; i--) {  
            if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {  
                ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);  
                if(anim.mAutoCancel && hasSameTargetAndProperties(anim)) { anim.cancel(); }}} / / whether Delay animation (Delay) and the current animation of the same animation, if you have the same animation to cancel numAnims = handler. MDelayedAnims. The size ();for (int i = numAnims - 1; i >= 0; i--) {  
            if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {  
                ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);  
                if(anim.mAutoCancel && hasSameTargetAndProperties(anim)) { anim.cancel(); } } } } super.start(); ValueAnimator star () is called because ObjectAnimator extends from ValueAnimator. } <-- the logical method that automatically assigns the value of an object attribute -- >> // Step 1: Private void setupValue(Object target, Keyframe kf) {if(mProperty ! = null) { kf.setValue(mProperty.get(target)); } kf.setValue(mget.invoke (target));} kf.setValue(mget.invoke (target)); }} // Step 2: Update the animation value // When the animation comes to the next frame (i.e. when the animation is updated),setAnimatedValue () is always called voidsetAnimatedValue(Object target) {  
    if(mProperty ! = null) { mProperty.set(target, getAnimatedValue()); // Internally call the property of the objectset() method to set the new property value to the object property}}Copy the code

Logic for automatic assignment:

  1. When initialized, if the initial value of the property is not provided, the property’sThe get ()Evaluate;
  2. When the value changes, the property of the object is usedSet ()Method to set the new property value to the object property.

So:

  • ObjectAnimator class is for any object & any property value, not just View object

  • If the ObjectAnimator class is used for animation, then the object to be manipulated must have set () & Get () for that property.

  • Similarly, for the other three basic animation effects above, There are also set () & Get () in views such as setRotation(), getRotation(), setTranslationX(), getTranslationX(), setScaleY(), getScaleY().


5.2.3 Achieve animation effects through custom object attributes

For attribute animation, its extensibility lies in: not limited to system-limited animation, you can customize animation, that is, customize the attributes of the object, and realize animation by manipulating the customized attributes.

So, how do you customize attributes? In essence, this is:

  • Set the set () & get () methods for objects that require action properties
  • The logic for property changes is defined by implementing the TypeEvaluator class

A procedure similar to ValueAnimator

Next, I will use an example to illustrate how to animate with custom properties

  • Achieved animation effect: a circular color gradient

  • The logic of the custom property is as follows :(requires custom property to be the background color of the circle)

Step 1: Set the set () & get () methods for the object class properties

There are two ways to set set () & get () for an object class property:

  1. Get () &set (); get () &set ();

  2. Get () & set () is indirectly added to the object by wrapping the original animation object. The original object is wrapped in a class

The first method is mainly used here.

The use of the second method is covered in more detail in the next section.

MyView2.java

Public class MyView2 extends View {public static finalfloatRADIUS = 100f; // Circle radius = 100 private Paint mPaint; // Drawing brush private String color; // Set the background color property // Set the background color get() &set() method public StringgetColor() {
        return color;
    }

    public void setColor(String color) { this.color = color; mPaint.setColor(Color.parseColor(color)); // Set the color of the brush to the color passed into the method parameter invalidate(); // Calls the invalidate() method, which refreshes the view every time the brush color changes, Then call onDraw() to redraw the circle // and since the color of the brush changes every time onDraw() is called, the color of the circle also changes} // Constructor (initialize the brush) public MyView2(Context Context, AttributeSet attrs) { super(context, attrs); // Initialize the paintbrush mPaint = new Paint(paint.anti_alias_flag); mPaint.setColor(Color.BLUE); } // Draw a circle at the initial point, by listening for the change of the current coordinate value (currentPoint), call onDraw() to redraw the circle, so as to achieve the translation effect @override protected  void onDraw(Canvas canvas) { canvas.drawCircle(500, 500, RADIUS, mPaint); }}Copy the code

Step 2: Add a custom View control to the layout file

activity_main.xml

<? xml version="1.0" encoding="utf-8"? > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="scut.carson_ho.valueanimator_ofobject.MainActivity">

    <scut.carson_ho.valueanimator_ofobject.MyView2
        android:id="@+id/MyView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         />
</RelativeLayout>
Copy the code

Step 3: Implement the TypeEvaluator interface as required

The essence of implementing the estimator here is to implement the logic of color transitions.

ColorEvaluator.java

Public class ColorEvaluator implements TypeEvaluator {// Implements TypeEvaluator; private int mCurrentGreen ; private int mCurrentBlue ; Public Object evaluate@override public Object evaluate()floatFraction, Object startValue, Object endValue) {String startColor = (String) startValue; String endColor = (String) endValue; // Divide the initialization color into three parts by string interception, Int startRed = integer.parseInt (startcolor.subString (1, 3), 16); int startGreen = Integer.parseInt(startColor.substring(3, 5), 16); int startBlue = Integer.parseInt(startColor.substring(5, 7), 16); int endRed = Integer.parseInt(endColor.substring(1, 3), 16); int endGreen = Integer.parseInt(endColor.substring(3, 5), 16); int endBlue = Integer.parseInt(endColor.substring(5, 7), 16); MCurrentRed = startRed; mCurrentRed = startRed; mCurrentGreen = startGreen; mCurrentBlue = startBlue; // Calculate the difference between the initial color and the end color // This difference determines the speed of the color change: the initial color and the end color are close, so the color change will be slow; Int redDiff = math.abs (startred-endred); int greenDiff = Math.abs(startGreen - endGreen); int blueDiff = Math.abs(startBlue - endBlue); int colorDiff = redDiff + greenDiff + blueDiff;if(mCurrentRed ! = endRed) { mCurrentRed = getCurrentColor(startRed, endRed, colorDiff, 0, fraction); // getCurrentColor() determines how fast the color changes based on the difference ->> focus on 1}else if(mCurrentGreen ! = endGreen) { mCurrentGreen = getCurrentColor(startGreen, endGreen, colorDiff, redDiff, fraction); }else if(mCurrentBlue ! = endBlue) { mCurrentBlue = getCurrentColor(startBlue, endBlue, colorDiff, redDiff + greenDiff, fraction); } // assembs the computed value of the currentColor with String currentColor ="#"+ getHexString(mCurrentRed) + getHexString(mCurrentGreen) + getHexString(mCurrentBlue); // Since the color we calculated is a decimal number, we need to convert it to a hexadecimal string: call getHexString()->> Focus on 2 // Finally assemble the RGB color and return it as the final resultreturncurrentColor; } // Focus on 1:getCurrentColor(); private int getCurrentColor(int startColor, int endColor, int colorDiff, int offset,float fraction) {
        int currentColor;
        if (startColor > endColor) {
            currentColor = (int) (startColor - (fraction * colorDiff - offset));
            if(currentColor < endColor) { currentColor = endColor; }}else {
            currentColor = (int) (startColor + (fraction * colorDiff - offset));
            if(currentColor > endColor) { currentColor = endColor; }}returncurrentColor; } // Concern 2: convert the base 10 color value to base 16. private String getHexString(int value) { String hexString = Integer.toHexString(value);if (hexString.length() == 1) {
            hexString = "0" + hexString;
        }
        returnhexString; }}Copy the code

Step 4: Call the ObjectAnimator.ofObject () method

MainActivity.java

public class MainActivity extends AppCompatActivity {

    MyView2 myView2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myView2 = (MyView2) findViewById(R.id.MyView2);
        ObjectAnimator anim = ObjectAnimator.ofObject(myView2, "color", new ColorEvaluator(),
                "#0000FF"."#FF0000"); // Set custom View object, background color attribute value & color estimator // Essential logic: // Step 1: change the value according to the color estimator // Step 2: callset// Step 3: Call invalidate() to refresh the view, that is, call onDraw () to redraw, thus animating anim.setDuration(8000); anim.start(); }}Copy the code

rendering

The source address

Github address for Carson_Ho


5.2.4 Special note: How to manually set set () & get () of object class attributes

A. background

  • ObjectAnimatorThe essence of a class’s automatic assignment of a property to an object is to call the set () & get () methods of that object’s property
  • So,ObjectAnimator.ofFloat(Object object, String property, float .... values)The second argument to is passed to letObjectAnimatorClass to find the property name of the object based on the property name passed inSet () & get ()Method to assign the value of an object property

According to the above principle, if the animation of property A of the object is to take effect, property A must satisfy the following two conditions:

  1. The object must provide the set () method of property A

A. If the initial value is not passed, then the get () method needs to be provided because the system is going to fetch the initial value of attribute A b. If this condition is not met, the program crashes

  1. Changes made to property A by the set () method of property A supplied by the object must be reflected in some way

B. If this item is not satisfied, the animation is invalid, but does not Crash)

The above conditions will generally be met in the second, mainly in the first

  1. As a result ofViewtheSetWidth ()It’s not settingViewThe width is set insteadViewOf the maximum and minimum width; So throughSetWidth ()Cannot change the width of the control. So forViewThe view ofwidthAnimating properties has no effect
  2. See the Button Button example below
Button mButton = (Button) findViewById(R.id.Button); Objectanimator.ofint (mButton, objectAnimator.ofint (mButton, objectAnimator.ofint)"width", 500).setDuration(5000).start(); // Set the object for the animationCopy the code

rendering

Why is there no animation? Let’s look at the setWidth method of View

public void setWidth(int pixels) {  
    mMaxWidth = mMinWidth = pixels;  
    mMaxWidthMode = mMinWidthMode = PIXELS; / / becausesetWidth () does not set the Width of the View, but sets the maximum and minimum Width of the Button // so it passessetRequestLayout (); Width () can't change the Width of the control. invalidate(); } @ViewDebug.ExportedProperty(category ="layout")  
public final int getWidth() {  
    returnmRight - mLeft; // getWidth does get the width of the View}Copy the code

B. the problem

So what if the set () for the above object property is not a set property or has no set ()/get () at all?

C. Solutions

Manually set the set () & get () of the object class properties. There are two methods:

  1. Get () &set (); get () &set ();

  2. Get () & set () is indirectly added to the object by wrapping the original animation object. The original object is wrapped in a class

The first method is illustrated in the example above; We’ll focus on the second method: indirectly add get () & set () to the object by wrapping the original animation object.

Essentially, the decorator pattern in the design pattern extends the functionality of an object by wrapping classes

Again, take the Button Button example above

public class MainActivity extends AppCompatActivity {
    Button mButton;
    ViewWrapper wrapper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.Button); Wrapper = new ViewWrapper(mButton); / / create the wrapper classes, and the object of the incoming animation role mButton. SetOnClickListener (new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(3000).start(); // Set the object of the animation to the object of the wrapper class}}); } private static class ViewWrapper {private View mTarget; Public ViewWrapper(View target) {mTarget = target; } // Set get () & for the widthset() public intgetWidth() {
            return mTarget.getLayoutParams().width;
        }

        public void setWidth(int width) { mTarget.getLayoutParams().width = width; mTarget.requestLayout(); }}}Copy the code

rendering


5.4 summarize

  • contrastValueAnimatorClass &ObjectAnimatorClass, both of which are property animations, are essentially the same: change the value and then assign it to the property of the object to animate it.
  • But the difference is this:ValueAnimatorThe class changes the value first, and thenManual assignmentTo animate objects with properties; isindirectPerform operations 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


6. Additional use methods

6.1 Composite Animation (AnimatorSet class)

  • The effects achieved by a single animation are quite limited, and more scenes are used at the same time using a variety of animation effects, that is, combination animation
  • Realize the function of combination animation:AnimatorSetclass
  • Specific use:
Animatorset. play(Animator anim) : Play the current animation animatorSet. after(long delay) : execute animatorSet. with(Animator anim) : Execute animatorSet. after(Animator anim) : Execute animatorSet. before(Animator anim) after inserting the existing animation into the incoming animation: Inserts the existing animation before the incoming animationCopy the code
  • The main animation of the example is translation, which is accompanied by rotation animation in the process of translation, and transparency changes after translation

This can be done in XML Settings/Java code Settings

Setting Mode 1:JavaCode sets

ObjectAnimator Translation = objectAnimator. ofFloat(mButton,"translationX", curTranslationX, 300,curTranslationX); Rotate = ObjectAnimator. Rotate (mButton,"rotation", 0f, 360f); ObjectAnimator alpha = objectAnimator.offloat (mButton,"alpha", 1f, 0f, 1f); AnimatorSet animSet = new AnimatorSet(); // Step 3: Combine animset.play (translation).with(rotate).before(alpha); animSet.setDuration(5000); // Step 4: Start animset.start ();Copy the code

rendering

Setting Mode 2:XMLSet up the

  • Step 1: Inres/animatorCreate an animation in the folder.xmlfile

Here for res/animator/set_animation. XML

  • Step 2: Set the animation effects

set_animation.xml

<? xml version="1.0" encoding="utf-8"? > <set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially"< // Set values :sequentially & together // sequentiallyset(b) // togethersetAnimation in, at the same time, default <set android:ordering="together"<objectAnimator android:duration="2000"
            android:propertyName="translationX"
            android:valueFrom="0"
            android:valueTo="300"
            android:valueType="floatType" >
        </objectAnimator>
        
        <objectAnimator
            android:duration="3000"
            android:propertyName="rotation"
            android:valueFrom="0"
            android:valueTo="360"
            android:valueType="floatType" >
        </objectAnimator>
    </set>

        <set android:ordering="sequentially"<objectAnimator android:duration="1500"
                android:propertyName="alpha"
                android:valueFrom="1"
                android:valueTo="0"
                android:valueType="floatType" >
            </objectAnimator>
            <objectAnimator
                android:duration="1500"
                android:propertyName="alpha"
                android:valueFrom="0"
                android:valueTo="1"
                android:valueType="floatType" >
            </objectAnimator>
        </set>

</set>
Copy the code

Start the animation in Java code

mButton = (Button) findViewById(R.id.Button); // Create an animation object: Here in the Button, for example AnimatorSet animator = (AnimatorSet) AnimatorInflater. LoadAnimator (this, state Richard armitage nimator. Set_animation); // Create a composite animation object & load the XML animation animator.settarget (mButton); // Set animator.start(); // Start animationCopy the code

rendering

Same as the first way.


6.2 ViewPropertyAnimator usage

  • As you can see from the above, the essence of property animation is value manipulation
  • butJavaIt’s object-oriented, soGoogleThe team adds object-oriented operations to the property animation using –ViewPropertyAnimatorclass

Think of it as a shorthand for property animation

  • The specific use
View.animate().xxx().xxx(); // The return value of the animate() method is a ViewPropertyAnimator object. All subsequent calls are made through this instance // ViewPropertyAnimator all interface methods are designed using concatenation syntax, MButton = (Button) findViewById(R.id.button); mButton = (Button) findViewById(R.id.button); Mbutton.animate ().alpha(0f); // Single animation setting: make buttons transparent mbutton.animate ().alpha(0f).setDuration(5000).setinterpolator (new BounceInterpolator()); Mbutton.animate ().alpha(0f).x(500).y(500); // Make the buttons transparent and move to (500,500) // Special note: // Animation starts automatically without calling the start() method. Since the new interface uses the implicit start animation function, the animation will start automatically as soon as we define the animation. This mechanism also works for composite animation, as long as new methods are continuously concatenated, the animation will not execute immediately. After all the methods set on ViewPropertyAnimator have been executed, the animation will start automatically // If you don't want to use this default mechanism, you can also explicitly call the start() method to start the animationCopy the code

6.3 Listening animation

  • AnimationClass listens for animation start/end/repeat/cancel moments to perform a series of actions, such as jumping to a page, etc
  • Through theJavaIn the codeAddListener ()Set up the
      Animation.addListener(new AnimatorListener() {@override public void onAnimationStart(Animation Animation) {@override public void onAnimationStart(Animation Animation) OnAnimationRepeat (Animation) {Override public void onAnimationCancel()(Animation) { Override public void onAnimationEnd(Animation Animation) {Override public void onAnimationEnd(Animation Animation)}}); // Note that all four methods must be overridden for each listener.Copy the code
  • Due to theAnimatorClass,AnimatorSetClass,ValueAnimator,ObjectAnimatorClasses have the following inheritance relationships

  • soAnimatorSetClass,ValueAnimator,ObjectAnimatorYou can use itaddListener()Listeners perform animated listening

Animation adapter AnimatorListenerAdapter

  • Background: Sometimes we don’t need to listen to the animation at all times
  • Question: butaddListener(new AnimatorListener())Listeners have to override the four time methods, making interface method overrides too cumbersome
  • Solution: Use the animation adapter (AnimatorListenerAdapter),Interface complexityThe problem of
anim.addListener(new AnimatorListenerAdapter() {// Pass the adapter object AnimatorListenerAdapter() to the addListener() method Override public void onAnimationStart(Animator animation) {Override public void onAnimationStart(Animator animation) {Copy the code

At this point, Android animation property animation in all the knowledge is explained.


7. To summarize

  • The essential principle of attribute animation: 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; The specific working principle is as follows:
  • Property animation is mainly used in the following classes, as follows:


  • Next, I I will continue to **AndroidAnimation ** for analysis, interested can continue to pay attention toCarson_Ho android Development Notes

Thumb up, please! Because your approval/encouragement is my biggest motivation to write!


Welcome to follow Carson_ho on wechat

  • aboutAndroidSeries of articles on animation
    1. This is a very detailed property animation summary & walkthrough Android animation: Hand-by-hand teach you to use tween animation Android frame by frame animation: about the use of frame by frame animation are here! Android Animation: Do you really know how to use interpolators and estimators? (including detailed example teaching)
    2. The principle of custom View, please refer to the article: (1) custom View basis – the most understandable custom View principle series (2) custom View Measure process – the most understandable custom View principle series (3) custom View Layout process – the most understandable custom View principle series (4) custom View Draw process – the most understandable custom View principle series
    3. Custom View application, please refer to the article: Why doesn’t your custom View wrap_content work? Why doesn’t wrap_content work?