Android在3.0之前只提供了兩種動畫:View Animation 、Drawable Animation 。也就是我們在《Android 動畫——Frame Animation與Tween Animation 》講解的逐幀動畫和補間動畫。Android在3.0之後又增加了一種動畫類型:Property Animation屬性動畫 。
View Animation相當簡單,不過只能支持簡單的縮放、平移、旋轉、透明度基本的動畫,且有一定的侷限性。比如:你希望View有一個顏色的切換動畫;你希望可以使用3D旋轉動畫;你希望當動畫停止時,View的位置就是當前的位置;這些View Animation都無法做到。這就是Property Animation產生的原因,本篇博客詳細介紹Property Animation的用法。
相關API
相關屬性:
Duration:動畫的持續時間,默認300ms。
Interpolation:時間差值,定義動畫的變化率。
RepeatCount:重複次數,可以定義重複多少次。
RepeatMode:重複模式,重複播放時,是從頭開始播還是反向播。
Animator sets: 動畫集合,你可以定義一組動畫,一起執行或者順序執行。
Frame refresh delay:幀刷新延遲,動畫多久刷新一次幀;默認爲10ms。
相關類:
ValueAnimator 動畫的執行類。
ObjectAnimator 動畫的執行類,ValueAnimator的子類。
AnimatorSet 用於控制一組動畫的執行:線性,一起,每個動畫的先後執行等。
AnimatorInflater 用戶加載屬性動畫的xml文件。
TypeEvaluator 類型估值,主要用於設置動畫操作屬性的值。
TimeInterpolator 時間插值。
Animator
Animator是動畫屬性的基類(父類),我們先看一下它的繼承結構:
Animator有兩個子類:
ValueAnimator :是屬性動畫的時間引擎,主要用於爲屬性動畫計算相關屬性的值。它也包含兩個子類:ObjectAnimator,TimeAnimator 。
AnimatorSet:用於組合多個Animator。
ValueAnimator的使用
ValueAnimator使用代碼創建和它的子類ObjectAnimator使用代碼創建是有區別的。這裏先聲明一下,在下面講解到ObjectAnimator我們會具體的說明。ValueAnimator使用代碼創建步驟如下:
1. 首先調用ValueAnimator如下的靜態方法設置相關的屬性值:
這裏我們調用ofFloat(float… values)屬性傳入動畫在X軸上變化的數值。
2. ValueAnimator對象調用setTarget()方法,設置動畫實現在哪個對象的身上。
3. ValueAnimator對象調用setDuration()和start()設置動畫的顯示時間和開始動畫。
4. 調用addUpdateListener()方法,在這個監聽器中添加相關的操作。
我們來看具體的代碼操作:
xml佈局文件:(一個按鈕開始動畫,一個ImageView顯示動畫)
<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"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<Button
android:id="@+id/button_start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="開始動畫" />
</LinearLayout>
<ImageView
android:id="@+id/imageview_xml"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:onClick="startAnimation"
android:src="@mipmap/ic_launcher" />
</RelativeLayout>
Activity代碼實現:
public class XMLAnimationActivity extends Activity implements View.OnClickListener {
private Button mButtonStart;
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xmlanimation);
mButtonStart = (Button) findViewById(R.id.button_start);
mImageView = (ImageView) findViewById(R.id.imageview_xml);
mButtonStart.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_start:
//在代碼中創建
ValueAnimator animator = ValueAnimator.ofFloat(0.0f, 1.0f);//設置屬性值
animator.setTarget(mImageView);//設置操作對象
animator.setDuration(1000).start();//動畫開始
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setScaleY((Float) animation.getAnimatedValue());//設置Y軸上的變化
mImageView.setScaleX((Float) animation.getAnimatedValue());//設置X軸上的變化
}
});
break;
default:
break;
}
}
}
ObjectAnimator的使用
ObjectAnimator創建有兩種方式,一種是在java代碼中添加,一種是使用加載xml佈局添加。
java代碼中創建
在Activity中添加一句話:
ObjectAnimator.ofFloat(mImageView, "ScaleX", 0.0f, 1.0f).setDuration(3000).start();
ObjectAnimator提供了ofInt、ofFloat、ofObject,這幾個方法都是設置動畫作用的元素、作用的屬性、動畫開始、結束、以及中間的任意個屬性值。當對於屬性值,只設置一個的時候,會認爲當然對象該屬性的值爲開始(getPropName反射獲取),然後設置的值爲終點。如果設置兩個,則一個爲開始、一個爲結束。
動畫更新的過程中,會不斷調用setPropName更新元素的屬性,所有使用ObjectAnimator更新某個屬性,必須得有getter(設置一個屬性值的時候)和setter方法。
xml文件中創建
爲了減輕java代碼的負擔,我們將對動畫的設置定義在xml代碼中。
1. 首先在res文件夾下創建一個animator的文件夾。
2. 在animator文件夾下創建一個animator.xml的文件。我們在該xml文件下對動畫屬性定義。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="3000"
android:propertyName="scaleX"
android:valueFrom="0.5f"
android:valueTo="1.0f">
</objectAnimator>
</set>
3. 在Activity中:
//使用xml文件加載屬性動畫方式一
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.animator);//通過該方法,將xml文件導入
anim.setTarget(mImageView);//這是動畫的對象
anim.start();//設置動畫的開始
以下爲補充:
其實在之前還有一種調用方式:在ImageView中添加android:onClick="startAnimation"
屬性,然後再Activity中定義如下方法:
注意:該方法已被拋棄,因爲他增加了xml佈局文件與java文件的耦合性,違背了”高內聚,低耦合“的原則。
public void startAnimation(View view) {
//java代碼中設置屬性操作
ObjectAnimator.ofFloat(mImageView, "TranslationZ", 0.0f, 1.0f).setDuration(3000).start();
}
public void startAnimation(View view) {
//xml文件中設置屬性操作
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.animator);
anim.setTarget(mImageView);
anim.start();
}
ObjectAnimator與ValueAnimator的不同
我們可以先回顧一下ValueAnimator的使用:
ValueAnimator animator = ValueAnimator.ofFloat(0.0f, 1.0f);//設置屬性值
animator.setTarget(mImageView);//設置操作對象
animator.setDuration(1000).start();//動畫開始
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setScaleY((Float) animation.getAnimatedValue());//設置Y軸上的變化
mImageView.setScaleX((Float) animation.getAnimatedValue());//設置X軸上的變化
}
});
ObjectAnimator使用:
ObjectAnimator.ofFloat(mImageView, "ScaleX", 0.0f, 1.0f).setDuration(3000).start();
區別很明顯,ValueAnimator調用ofFloat()方法設置了操作的值,而沒有設置是何種操作,也就是沒有設置操作屬性。而ObjectAnimator調用ofFloat()方法設置了操作屬性是ScaleX(X軸變化)。
ValueAnimator有沒有設置操作的屬性,也就是說我們必須在addUpdateListener()方法中定義的監聽器中添加相關的屬性,否則動畫沒有任何的操作。那麼ValueAnimator這樣有什麼好處呢?
好處就是,我們不需要操作的對象的屬性一定要有getter和setter方法,你可以自己根據當前動畫的計算值,來操作任何屬性。