Android Animation Collection Attribute Animation - First Look


Introduction to this section:

This section brings the third type of animation in Android animation-Property Animation. Remember in the previous section 8.4.2 Android Animation Collection Tween Animation is Fragment When setting the transition animation, I mentioned that the Fragment under the App package and V4 package calls setCustomAnimations() correspondingly. The animation types are different. The one under the v4 package is Animation, while the one under the app package is Animator;

Animation general animation is The frame animation and tween animation we learned earlier! Animator is the attribute animation that we will talk about in this section!

Regarding attribute animation, Daniel Guo has written three very good summary articles. They are very well written. There is no need to reinvent the wheel. But let’s go over it here. Most of the content refers to the following three articles:

Complete analysis of Android attribute animation (Part 1), first understanding of the basic usage of attribute animation

Complete analysis of Android property animation (Part 2), advanced usage of ValueAnimator and ObjectAnimator

Complete analysis of Android property animation (Part 2), usage of Interpolator and ViewPropertyAnimator

The writing is very good, or you can skip this article directly and read the three articles above~

Of course, if you are willing to read my babble, you are also very welcome. Okay, let’s start this section. Let’s talk about the content~


1. The concept of attribute animation is so confusing


No BB, just go to the picture, it’s so violent~

1.jpg


2. Simple use of ValueAnimator

Usage process:

  • 1. Call ValueAnimator’s ofInt() , ofFloat() or ofObject() static method to create a ValueAnimator instance
  • 2. Call the setXxx method of the instance to set the animation duration, interpolation method, number of repetitions, etc.
  • 3. Call the addUpdateListener of the instance to add the AnimatorUpdateListener listener in the listener You can get the value calculated by ValueAnimator, and you can apply the value to the specified object~
  • 4. Call the start() method of the instance to start the animation! In addition, we can see that both ofInt and ofFloat have such parameters: float/int... values ​​represent multiple values!

Usage example:

2.gif

##Code implementation:

Layout file :

activity_main.xml, very simple, four buttons, one ImageView

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ly_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="动画1" />

    <Button
        android:id="@+id/btn_two"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="动画2" />

    <Button
        android:id="@+id/btn_three"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="动画3" />

    <Button
        android:id="@+id/btn_four"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="动画4" />

    <ImageView
        android:id="@+id/img_babi"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@mipmap/img_babi" /></LinearLayout>

Then go to MainActivity.java, First, we need a method to modify the View position. Here we call moveView() to set the starting coordinates of the left and top as well as the width and height!

Then four animations are defined, namely: linear movement, scaling, rotation with transparency, and circular rotation!

Then trigger the corresponding animation through the button~

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn_one;
    private Button btn_two;
    private Button btn_three;
    private Button btn_four;
    private LinearLayout ly_root;
    private ImageView img_babi;
    private int width;
    private int height;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
    }

    private void bindViews() {
        ly_root = (LinearLayout) findViewById(R.id.ly_root);
        btn_one = (Button) findViewById(R.id.btn_one);
        btn_two = (Button) findViewById(R.id.btn_two);
        btn_three = (Button) findViewById(R.id.btn_three);
        btn_four = (Button) findViewById(R.id.btn_four);
        img_babi = (ImageView) findViewById(R.id.img_babi);

        btn_one.setOnClickListener(this);
        btn_two.setOnClickListener(this);
        btn_three.setOnClickListener(this);
        btn_four.setOnClickListener(this);
        img_babi.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_one:
                lineAnimator();
                break;
            case R.id.btn_two:
                scaleAnimator();
                break;
            case R.id.btn_three:
                raAnimator();
                break;
            case R.id.btn_four:
                circleAnimator();
                break;
            case R.id.img_babi:
                Toast.makeText(MainActivity.this, "不愧是coder-pig~", Toast.LENGTH_SHORT).show();
                break;
        }
    }


    //定义一个修改ImageView位置的方法
    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);
    }


    //定义属性动画的方法:

    //按轨迹方程来运动
    private void lineAnimator() {
        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) {
                // 轨迹方程 x = width / 2
                int y = (Integer) animation.getAnimatedValue();
                int x = width / 2;
                moveView(img_babi, x, y);
            }
        });
        xValue.setInterpolator(new LinearInterpolator());
        xValue.start();
    }

    //缩放效果
    private void scaleAnimator(){
    
        //这里故意用两个是想让大家体会下组合动画怎么用而已~
        final float scale = 0.5f;
        AnimatorSet scaleSet = new AnimatorSet();
        ValueAnimator valueAnimatorSmall = ValueAnimator.ofFloat(1.0f, scale);
        valueAnimatorSmall.setDuration(500);

        ValueAnimator valueAnimatorLarge = ValueAnimator.ofFloat(scale, 1.0f);
        valueAnimatorLarge.setDuration(500);

        valueAnimatorSmall.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float scale = (Float) animation.getAnimatedValue();
                img_babi.setScaleX(scale);
                img_babi.setScaleY(scale);
            }
        });
        valueAnimatorLarge.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float scale = (Float) animation.getAnimatedValue();
                img_babi.setScaleX(scale);
                img_babi.setScaleY(scale);
            }
        });

        scaleSet.play(valueAnimatorLarge).after(valueAnimatorSmall);
        scaleSet.start();

        //其实可以一个就搞定的
//        ValueAnimator vValue = ValueAnimator.ofFloat(1.0f, 0.6f, 1.2f, 1.0f, 0.6f, 1.2f, 1.0f);
//        vValue.setDuration(1000L);
//        vValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation) {
//                float scale = (Float) animation.getAnimatedValue();
//                img_babi.setScaleX(scale);
//                img_babi.setScaleY(scale);
//            }
//        });
//        vValue.setInterpolator(new LinearInterpolator());
//        vValue.start();
    }


    //旋转的同时透明度变化
    private void raAnimator(){
        ValueAnimator rValue = ValueAnimator.ofInt(0, 360);
        rValue.setDuration(1000L);
        rValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int rotateValue = (Integer) animation.getAnimatedValue();
                img_babi.setRotation(rotateValue);
                float fractionValue = animation.getAnimatedFraction();
                img_babi.setAlpha(fractionValue);
            }
        });
        rValue.setInterpolator(new DecelerateInterpolator());
        rValue.start();
    }

    //圆形旋转
    protected void circleAnimator() {
        width = ly_root.getWidth();
        height = ly_root.getHeight();
        final int R = width / 4;
        ValueAnimator tValue = ValueAnimator.ofFloat(0,
                (float) (2.0f * Math.PI));
        tValue.setDuration(1000);
        tValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 圆的参数方程 x = R * sin(t) y = R * cos(t)
                float t = (Float) animation.getAnimatedValue();
                int x = (int) (R * Math.sin(t) + width / 2);
                int y = (int) (R * Math.cos(t) + height / 2);
                moveView(img_babi, x, y);
            }
        });
        tValue.setInterpolator(new DecelerateInterpolator());
        tValue.start();
    }
}

Okay, the process is very simple. First create the ValueAnimator object and call ValueAnimator.ofInt/ofFloat Get, then set the animation duration, addUpdateListenerAdd AnimatorUpdateListener event listening, Then use getAnimatedValue() of parameter animation to get the current value, and then we can hold this value To modify some properties of the View to form the so-called animation effect, and then set the setInterpolator animation rendering mode, Finally, start() is called to start the animation playback~

Damn it, the equation of a straight line, the parametric equation of a circle, I’m starting to get square, isn’t this something high-level mathematics? The scientific scumbag even forgot about trigonometric functions...3.gif

The example is from github:MoveViewValueAnimator


3. Simple use of ObjectAnimator

Compared with ValueAnimator, ObjectAnimator is easier to use. Through this class, we can directly animate any property of any object! That's right, it's any object, not just View objects. Continuously assign a certain attribute value in the object, and then decide how to display it based on the change in the object attribute value. come out! For example, set the following animation for TextView: ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f);
Here is to continuously change the value of alpha, from 1f - 0f, and then the object changes according to the attribute value changes to refresh the interface display, thus Shows the effect of fading in and out, but there is no alpha attribute in the TextView class. The internal mechanism of ObjectAnimator is: Look for the get and set methods corresponding to the transferred attribute names~, instead of looking for the attribute value! If you don’t believe it, you can check the source code of TextView to see if there is an alpha attribute! Okay, let’s use ObjectAnimator to achieve the effects of four types of tween animation~

Running renderings:

4.gif

Code implementation:

The layout directly uses the above layout, adds a button, and replaces the ImageView with a TextView. The code will not be posted here. Go directly to the MainActivity.java part of the code. In fact, they are all the same~

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn_one;
    private Button btn_two;
    private Button btn_three;
    private Button btn_four;
    private Button btn_five;
    private LinearLayout ly_root;
    private TextView tv_pig;
    private int height;
    private ObjectAnimator animator1;
    private ObjectAnimator animator2;
    private ObjectAnimator animator3;
    private ObjectAnimator animator4;
    private AnimatorSet animSet;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
        initAnimator();
    }

    private void bindViews() {
        ly_root = (LinearLayout) findViewById(R.id.ly_root);
        btn_one = (Button) findViewById(R.id.btn_one);
        btn_two = (Button) findViewById(R.id.btn_two);
        btn_three = (Button) findViewById(R.id.btn_three);
        btn_four = (Button) findViewById(R.id.btn_four);
        btn_five = (Button) findViewById(R.id.btn_five);
        tv_pig = (TextView) findViewById(R.id.tv_pig);

        height = ly_root.getHeight();
        btn_one.setOnClickListener(this);
        btn_two.setOnClickListener(this);
        btn_three.setOnClickListener(this);
        btn_four.setOnClickListener(this);
        btn_five.setOnClickListener(this);
        tv_pig.setOnClickListener(this);
    }

    //初始化动画
    private void initAnimator() {
        animator1 = ObjectAnimator.ofFloat(tv_pig, "alpha", 1f, 0f, 1f, 0f, 1f);
        animator2 = ObjectAnimator.ofFloat(tv_pig, "rotation", 0f, 360f, 0f);
        animator3 = ObjectAnimator.ofFloat(tv_pig, "scaleX", 2f, 4f, 1f, 0.5f, 1f);
        animator4 = ObjectAnimator.ofFloat(tv_pig, "translationY", height / 8, -100, height / 2);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_one:
                animator1.setDuration(3000l);
                animator1.start();
                break;
            case R.id.btn_two:
                animator2.setDuration(3000l);
                animator2.start();
                break;
            case R.id.btn_three:
                animator3.setDuration(3000l);
                animator3.start();
                break;
            case R.id.btn_four:
                animator4.setDuration(3000l);
                animator4.start();
                break;
            case R.id.btn_five:
                //将前面的动画集合到一起~
                animSet = new AnimatorSet();
                animSet.play(animator4).with(animator3).with(animator2).after(animator1);
                animSet.setDuration(5000l);
                animSet.start();
                break;
            case R.id.tv_pig:
                Toast.makeText(MainActivity.this, "不愧是coder-pig~", Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

The usage is also very simple. We will talk about the combined animations mentioned above~


4. Combined animation and AnimatorListener

From the above two examples, we have experienced a combined animation, using the AnimatorSet class!

We call the play() method, and then pass in the first animation to start execution. At this time, it will return a Builder class to us:

5.png

Next We can call the four methods provided by Builder to combine other animations:

  • after(Animator anim) Insert the existing animation into the incoming animation and execute it
  • after(long delay) Delay the existing animation for specified milliseconds before executing
  • before(Animator anim) Insert the existing animation into the passed animation Execute before the incoming animation
  • with(Animator anim) Execute the existing animation and the incoming animation at the same time

Well, it’s very simple, next Let’s talk about the monitoring of animation events. The listener of our ValueAnimator above is AnimatorUpdateListener. When the value status changes, the onAnimationUpdate method will be called back!

In addition to this kind of event, there are also: monitoring of animation progress~ AnimatorListener, we can call the addListener method Add a listener, and then override the following four callback methods:

  • onAnimationStart(): animation starts
  • onAnimationRepeat(): Animation is executed repeatedly
  • onAnimationEnd(): Animation ends
  • onAnimationCancel(): Animation is canceled

Yes , if you really use AnimatorListener, you have to rewrite all four methods. Of course, it is the same as the previous gesture section. Android has provided us with an adapter class: AnimatorListenerAdapter, in which each interface has been The methods are all implemented, so we can just write a callback method here!


5. Use XML to write animations

Using XML to write animations may take a little longer to draw than Java code, but it is much easier to reuse! The corresponding XML tags are: <animator><objectAnimator><set> The relevant attributes are explained as follows:

  • android:ordering: Specify the playback order of animations: sequentially (sequential execution), together (simultaneous execution)
  • android:duration: The duration of the animation
  • android:propertyName="x": The x here, remember the "alpha" above? Required in the object that loads the animation Define the methods of getx and setx, which is how objectAnimator modifies the value in the object!
  • android:valueFrom="1": The initial value of the animation start
  • android:valueTo="0": The final value of the animation end Value
  • android:valueType="floatType": Change the data type of the value

Usage examples are as follows:

Animation of smooth transition from 0 to 100

<animator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:valueFrom="0"  
    android:valueTo="100"  
    android:valueType="intType"/>

Change the alpha attribute of a view from 1 to 0:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:valueFrom="1"  
    android:valueTo="0"  
    android:valueType="floatType"  
    android:propertyName="alpha"/>

set animation usage demonstration:

 <set android:ordering="sequentially" >
    <set>
        <objectAnimator
            android:duration="500"
            android:propertyName="x"
            android:valueTo="400"
            android:valueType="intType" />
        <objectAnimator
            android:duration="500"
            android:propertyName="y"
            android:valueTo="300"
            android:valueType="intType" />
    </set>
    <objectAnimator
        android:duration="500"
        android:propertyName="alpha"
        android:valueTo="1f" /></set>

Load our animation file:

AnimatorSet set = (AnimatorSet)AnimatorInflater.loadAnimator(mContext, 
             R.animator.property_animator);  
animator.setTarget(view);  
animator.start();

6. Download the sample code for this section:

AnimatorDemo1.zip

AnimatorDemo2.zip


Summary of this section:

Okay, this section will give you a brief introduction to the basic usage of attribute animation in Android. I don’t know if you got it, but the content is relatively simple. , and the examples are quite interesting, I believe everyone will like it, well, that’s all, thank you~

ThanksGuo Shen for the article~

6.jpg