Easy Tutorial
❮ Python Complex Intro Verilog Process Structure ❯

8.4.3 Android Animation Collection - Property Animation - First Encounter

Category Android Basic Introduction Tutorial

Introduction:

This section introduces the third type of animation in Android—Property Animation (Property Animation). In the previous section 8.4.2 Android Animation Collection - Tween Animation, when setting transition animations for Fragments, it was mentioned that the types of animations used by Fragments in the v4 package and the app package are different. The v4 package uses Animation, while the app package uses Animator.

Animation, the general animation, includes the Frame Animation and Tween Animation we learned earlier! Animator is the Property Animation that we will discuss in this section!

Regarding Property Animation, the expert Guo Lin has written three excellent summary articles, which are highly praised and there is no need to reinvent the wheel. However, we will still go through the basics here, with most content referenced from the following three articles:

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

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

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

These articles are highly recommended, or you can skip this article and go directly to the above three articles.

Of course, if you prefer to listen to my detailed explanation, you are also welcome. Let's start with this section's content.


1. Concept of Property Animation


No more talking, let's jump to the pictures, straightforward and violent~


2. Simple Usage of ValueAnimator

Usage Process:

Usage Example:

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="Animation 1" />

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

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

    <Button
        android:id="@+id/btn_four"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Animation 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>

Next is MainActivity.java. First, a method to modify the View's position is needed. Here, moveView() is called to set the starting coordinates and dimensions.

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

Finally, the corresponding animations are triggered by buttons.

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, "Indeed, coder-pig~", Toast.LENGTH_SHORT).show();
                break;
        }
    }


    // Method to modify the ImageView's position
    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);
    }


    // Define property animation methods:

    // Move along a trajectory equation
    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) {
                // Trajectory equation x = width / 2
int y = (Integer) animation.getAnimatedValue();
int x = width / 2;
moveView(img_babi, x, y);
}
});
xValue.setInterpolator(new LinearInterpolator());
xValue.start();
}

// Scale effect
private void scaleAnimator() {

// This is intentionally done with two to help understand how to use combined animations
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();

// Actually, one would be enough
// 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();
}

// Rotate while changing opacity
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();
}

// Circular rotation
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) {
// Parametric equation of a circle 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();
}
}

The process is quite straightforward: first, create a ValueAnimator object, call ValueAnimator.ofInt/ofFloat to obtain it, then set the duration of the animation, addUpdateListener to add an AnimatorUpdateListener event listener, and use the parameter animation's getAnimatedValue() to get the current value. With this value, we can modify some properties of the View to create the so-called animation effect. Next, set the setInterpolator animation rendering mode and finally call start() to start the animation playback.

Wow, linear equations, parametric equations of a circle, I'm starting to feel overwhelmed. These are things from advanced mathematics, and I've forgotten even trigonometric functions as a failed student...

Example referenced from GitHub: MoveViewValueAnimator


3. Simple Use of ObjectAnimator

Compared to ValueAnimator, ObjectAnimator is easier to use. With this class, we can directly animate any property of any object! Yes, any object, not just View objects. It continuously assigns values to a property of an object, and then decides how to display based on the changes in the property values. For example, to set an animation for a TextView: ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f); It looks for the get and set methods corresponding to the property name being passed, not the property value itself! If you don't believe me, you can look for the "alpha" property in the TextView source code.

Alright, let's use ObjectAnimator to achieve four types of tween animations.

Running Effect Diagram:

Code Implementation:

The layout is directly reused from the previous one, with a button added and the ImageView replaced with a TextView. I won't post the code here, just the MainActivity.java part, which is mostly similar.

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

// Initialize animation
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:
// Combine previous animations
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, "Indeed, coder-pig~", Toast.LENGTH_SHORT).show();
break;
}
}
}

Usage is also very simple, the combined animations we mentioned above will be discussed below~


4. Combined Animations and AnimatorListener

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

We call the play() method and pass in the first animation to start, which returns a Builder class to us:

Next, we can use the four methods provided by the Builder to combine other animations:

It's simple. Next, let's talk about animation event listeners. Above, we used AnimatorUpdateListener, which calls the onAnimationUpdate method when the value changes.

In addition to this event, there are animation state listeners: AnimatorListener. We can call addListener to add a listener and override the following four callback methods:

If you use AnimatorListener, you need to override all four methods. Similar to the gesture section earlier, Android provides an adapter class: AnimatorListenerAdapter, which has already implemented each interface method. So, we can just write one callback method here.


5. Writing Animations in XML

Writing animations in XML might take a bit longer than Java code, but reusing them is much easier! The corresponding XML tags are: <animator>, <objectAnimator>, <set>.

Relevant attribute explanations are as follows:

Example usage:

Smooth transition animation from 0 to 100:

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

Animation to change the alpha property 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>

Loading our animation file:

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

6. Sample Code Download:

AnimatorDemo1.zip

AnimatorDemo2.zip


Summary:

>

Alright, this section has covered the basics of using property animations in Android. I hope you've got it. The content is relatively simple, and the examples are interesting, so I believe you'll enjoy them. That's all for now, thank you~

Thanks to Guo Shen for the article~

> -1.0 Android Basic Introduction Tutorial

-1.0.1 2015 Latest Android Basic Introduction Tutorial Contents

-1.1 Background and System Architecture Analysis

-1.2 Development Environment Setup

-1.2.1 Developing Android Apps with Eclipse + ADT + SDK

-1.2.2 Developing Android Apps with Android Studio

-1.3 Solving SDK Update Issues

-1.4 Genymotion Emulator Installation

-1.5.1 Git Tutorial: Basic Operations on Local Repository

-1.5.2 Git: Setting Up a Remote Repository on GitHub

-1.6 How to Use the "Nine Patch" Image

-1.7 Interface Prototype Design

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

-1.9 Android Application Signing and Packaging

-1.11 Decompiling APK to Retrieve Code & Resources

-2.1 Concepts of View and ViewGroup

-2.2.1 LinearLayout (Linear Layout)

-2.2.2 RelativeLayout (Relative Layout)

-2.2.3 TableLayout (Table Layout)

-2.2.4 FrameLayout (Frame Layout)

-2.2.5 GridLayout (Grid Layout)

-2.2.6 AbsoluteLayout (Absolute Layout)

-2.3.1 Detailed Explanation of TextView (Text Field)

-2.3.2 Detailed Explanation of EditText (Input Field)

-2.3.3 Button and ImageButton

-2.3.4 ImageView (Image View)

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

-2.3.6 ToggleButton and Switch

-2.3.7 ProgressBar (Progress Bar)

-2.3.8 SeekBar (Drag Bar)

-2.3.9 RatingBar (Star Rating Bar)

-2.4.1 ScrollView (Scroll Bar)

-2.4.2 Date & Time Components (Part 1)

-2.4.3 Date & Time Components (Part 2)

-2.4.4 Adapter Basics

-2.4.5 Simple Usage of ListView

-2.4.6 Optimization of BaseAdapter

-2.4.7 Focus Issues with ListView

-2.4.8 Solving Checkbox Misalignment in ListView

-2.4.9 Data Update Issues in ListView

-2.5.0 Building a Reusable Custom BaseAdapter

-2.5.1 Implementing Multiple Item Layouts in ListView

-2.5.2 Basic Usage of GridView (Grid View)

-2.5.3 Basic Usage of Spinner (List Option Box)

-2.5.4 Basic Usage of AutoCompleteTextView (Auto-Complete Text Field)

-2.5.5 Basic Usage of ExpandableListView (Collapsible List)

-2.5.6 Basic Usage of ViewFlipper (Flip View)

-2.5.7 Basic Usage of Toast

-2.5.8 Detailed Explanation of Notification (Status Bar Notification)

-2.5.9 Detailed Explanation of AlertDialog (Dialog Box)

-2.6.0 Basic Usage of Other Common Dialogs

-2.6.1 Basic Usage of PopupWindow (Floating Box)

-2.6.2 Menu (Menu)

-2.6.3 Simple Usage of ViewPager

-2.6.4 Simple Usage of DrawerLayout (Official Side Menu)

-3.1.1 Event Handling Mechanism Based on Listeners

-3.2 Event Handling Mechanism Based on Callbacks

-3.3 Analysis of Handler Message Passing Mechanism

-3.4 TouchListener vs OnTouchEvent + Multi-Touch

-3.5 Listening for Content Changes in EditText

-3.6 Responding to System Settings Changes (Configuration Class)

-3.7 AsyncTask Asynchronous Task

-3.8 Gestures (Gestures)

-4.1.1 Activity: Getting Started

-4.1.2 Activity: Intermediate

-4.1.3 Activity: Advanced

-4.2.1 Service: Introduction

-4.2.2 Service: Intermediate

-4.2.3 Service: Advanced

-4.3.1 BroadcastReceiver: Basic

-4.3.2 BroadcastReceiver: Advanced

-4.4.1 ContentProvider: Introduction

-4.4.2 ContentProvider: Advanced - Document Provider

-4.5.1 Basic Usage of Intent

-4.5.2 Passing Complex Data with Intent

-5.1 Basic Overview of Fragment

-5.2.1 Fragment Example: Bottom Navigation Bar Implementation (Method 1)

-5.2.2 Fragment Example: Bottom Navigation Bar Implementation (Method 2)

Follow on WeChat

❮ Python Complex Intro Verilog Process Structure ❯