0、基礎回顧
PropertyAnimation,屬性動畫,顧名思義就是利用對象的屬性變化形成動畫的效果。屬性動畫的類可以用Animator這個抽象類來表示,通常使用它的子類:AnimatorSet和ValueAnimator,同時ValueAnimator有兩個子類分別是ObjectAniamtor和TimeAnimator。
定義屬性動畫的XML資源的時候通常可以是如下三個元素之一作為根元素:
<set>元素:該資源元素代表的是AniamtorSet類,這個類可以包含<set>,<objectAniamtor>,<animator>三個子元素。
<objectAnimator>元素:用于定義objectAniamtor類。
<animator>元素:用于定義ValueAnimator類。
比如說這里一個資源文件的定義如下:
<set android:ordering="[together|sequentially]"> <objectAnimator android:propertyName="string" android:duration="int" android:valueFrom="float|int|color" android:valueTo="float|int|color" android:startOffset="int" android:repeatCount="int" android:interpolator="" android:repeatMode="[reapeat|reverse]" android:valueType="[intType|floatType]"/> <animator android:duration="int" android:valueFrom="float|int|color" android:valueTo="float|int|color" android:startOffset="int" android:repeatCount="int" android:interpolator="" android:repeatMode="[reapeat|reverse]" android:valueType="[intType|floatType]"/> <set> .... </set> </set>
屬性文件通常保存在animator文件夾下面。
1、如何使用xml文件來創建屬性動畫
大家肯定都清楚,View Animator 、Drawable Animator都可以在anim文件夾下創建動畫,然后在程序中使用,甚至在Theme中設置為屬性值。當然了,屬性動畫其實也可以在文件中聲明:
首先在res下建立animator文件夾,然后建立res/animator/scalex.xml
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:propertyName="scaleX" android:valueFrom="1.0" android:valueTo="2.0" android:valueType="floatType" > </objectAnimator>
代碼:
public void scaleX(View view)   {     // 加載動畫     Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scalex);     anim.setTarget(mMv);     anim.start();   } 使用AnimatorInflater加載動畫的資源文件,然后設置目標,就ok~~是不是很簡單,這只是單純橫向的放大一倍~
如果我希望縱向與橫向同時縮放呢?則可以怎么定義屬性文件:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together" > <objectAnimator android:duration="1000" android:propertyName="scaleX" android:valueFrom="1" android:valueTo="0.5" > </objectAnimator> <objectAnimator android:duration="1000" android:propertyName="scaleY" android:valueFrom="1" android:valueTo="0.5" > </objectAnimator> </set>
使用set標簽,有一個orderring屬性設置為together,【還有另一個值:sequentially(表示一個接一個執行)】。
上篇博客中忽略了一個效果,就是縮放、反轉等都有中心點或者軸,默認中心縮放,和中間對稱線為反轉線,所以我決定這個橫向,縱向縮小以左上角為中心點:
代碼:
// 加載動畫 Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scale); mMv.setPivotX(0); mMv.setPivotY(0); //顯示的調用invalidate mMv.invalidate(); anim.setTarget(mMv); anim.start();
很簡單,直接給View設置pivotX和pivotY,然后調用一下invalidate,就ok了。
下面看效果圖:

好了,通過寫xml聲明動畫,使用set嵌套set,結合orderring屬性,也基本可以實現任何動畫~~上面也演示了pivot的設置。
2、布局動畫(Layout Animations)
主要使用LayoutTransition為布局的容器設置動畫,當容器中的視圖層次發生變化時存在過渡的動畫效果。
基本代碼為:
LayoutTransition transition = new LayoutTransition(); transition.setAnimator(LayoutTransition.CHANGE_APPEARING, transition.getAnimator(LayoutTransition.CHANGE_APPEARING)); transition.setAnimator(LayoutTransition.APPEARING, null); transition.setAnimator(LayoutTransition.DISAPPEARING, null); transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, null); mGridLayout.setLayoutTransition(transition);
過渡的類型一共有四種:
(1)LayoutTransition.APPEARING 當一個View在ViewGroup中出現時,對此View設置的動畫
(2)LayoutTransition.CHANGE_APPEARING 當一個View在ViewGroup中出現時,對此View對其他View位置造成影響,對其他View設置的動畫
(3)LayoutTransition.DISAPPEARING  當一個View在ViewGroup中消失時,對此View設置的動畫
(4)LayoutTransition.CHANGE_DISAPPEARING 當一個View在ViewGroup中消失時,對此View對其他View位置造成影響,對其他View設置的動畫
(5)LayoutTransition.CHANGE 不是由于View出現或消失造成對其他View位置造成影響,然后對其他View設置的動畫。
注意動畫到底設置在誰身上,此View還是其他View。
好了下面看一個綜合的例子:
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/id_container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="addBtn" android:text="addBtns" /> <CheckBox android:id="@+id/id_appear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="APPEARING" /> <CheckBox android:id="@+id/id_change_appear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="CHANGE_APPEARING" /> <CheckBox android:id="@+id/id_disappear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="DISAPPEARING" /> <CheckBox android:id="@+id/id_change_disappear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="CHANGE_DISAPPEARING " /> </LinearLayout>
代碼:
package com.example.zhy_property_animation;  import android.animation.LayoutTransition; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.GridLayout;  public class LayoutAnimaActivity extends Activity implements     OnCheckedChangeListener {   private ViewGroup viewGroup;   private GridLayout mGridLayout;   private int mVal;   private LayoutTransition mTransition;    private CheckBox mAppear, mChangeAppear, mDisAppear, mChangeDisAppear;    @Override   public void onCreate(Bundle savedInstanceState)   {     super.onCreate(savedInstanceState);     setContentView(R.layout.layout_animator);     viewGroup = (ViewGroup) findViewById(R.id.id_container);      mAppear = (CheckBox) findViewById(R.id.id_appear);     mChangeAppear = (CheckBox) findViewById(R.id.id_change_appear);     mDisAppear = (CheckBox) findViewById(R.id.id_disappear);     mChangeDisAppear = (CheckBox) findViewById(R.id.id_change_disappear);      mAppear.setOnCheckedChangeListener(this);     mChangeAppear.setOnCheckedChangeListener(this);     mDisAppear.setOnCheckedChangeListener(this);     mChangeDisAppear.setOnCheckedChangeListener(this);      // 創建一個GridLayout     mGridLayout = new GridLayout(this);     // 設置每列5個按鈕     mGridLayout.setColumnCount(5);     // 添加到布局中     viewGroup.addView(mGridLayout);     //默認動畫全部開啟     mTransition = new LayoutTransition();     mGridLayout.setLayoutTransition(mTransition);    }    /**    * 添加按鈕    *    * @param view    */   public void addBtn(View view)   {     final Button button = new Button(this);     button.setText((++mVal) + "");     mGridLayout.addView(button, Math.min(1, mGridLayout.getChildCount()));     button.setOnClickListener(new OnClickListener()     {        @Override       public void onClick(View v)       {         mGridLayout.removeView(button);       }     });   }    @Override   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)   {     mTransition = new LayoutTransition();     mTransition.setAnimator(         LayoutTransition.APPEARING,         (mAppear.isChecked() ? mTransition             .getAnimator(LayoutTransition.APPEARING) : null));     mTransition         .setAnimator(             LayoutTransition.CHANGE_APPEARING,             (mChangeAppear.isChecked() ? mTransition                 .getAnimator(LayoutTransition.CHANGE_APPEARING)                 : null));     mTransition.setAnimator(         LayoutTransition.DISAPPEARING,         (mDisAppear.isChecked() ? mTransition             .getAnimator(LayoutTransition.DISAPPEARING) : null));     mTransition.setAnimator(         LayoutTransition.CHANGE_DISAPPEARING,         (mChangeDisAppear.isChecked() ? mTransition             .getAnimator(LayoutTransition.CHANGE_DISAPPEARING)             : null));     mGridLayout.setLayoutTransition(mTransition);   } } 效果圖:

動畫有點長,耐心點看,一定要注意,是對當前View還是其他Views設置的動畫。
當然了動畫支持自定義,還支持設置時間,比如我們修改下,添加的動畫為:
mTransition.setAnimator(LayoutTransition.APPEARING, (mAppear .isChecked() ? ObjectAnimator.ofFloat(this, "scaleX", 0, 1) : null));
則效果為:

原本的淡入,變成了寬度從中間放大的效果~~是不是還不錯~~
3、View的anim方法
在SDK11的時候,給View添加了animate方法,更加方便的實現動畫效果。
布局文件:
<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" > <ImageView android:id="@+id/id_ball" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/bol_blue" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="viewAnim" android:text="View Anim" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="propertyValuesHolder" android:text="PropertyValuesHolder " /> </LinearLayout> </RelativeLayout>
代碼:
package com.example.zhy_property_animation;  import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.app.Activity; import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.widget.ImageView;  public class ViewAnimateActivity extends Activity {   protected static final String TAG = "ViewAnimateActivity";    private ImageView mBlueBall;   private float mScreenHeight;    @Override   protected void onCreate(Bundle savedInstanceState)   {     super.onCreate(savedInstanceState);     setContentView(R.layout.view_animator);      DisplayMetrics outMetrics = new DisplayMetrics();     getWindowManager().getDefaultDisplay().getMetrics(outMetrics);     mScreenHeight = outMetrics.heightPixels;     mBlueBall = (ImageView) findViewById(R.id.id_ball);    }    public void viewAnim(View view)   {     // need API12     mBlueBall.animate()//         .alpha(0)//         .y(mScreenHeight / 2).setDuration(1000)         // need API 12         .withStartAction(new Runnable()         {           @Override           public void run()           {             Log.e(TAG, "START");           }           // need API 16         }).withEndAction(new Runnable()         {            @Override           public void run()           {             Log.e(TAG, "END");             runOnUiThread(new Runnable()             {               @Override               public void run()               {                 mBlueBall.setY(0);                 mBlueBall.setAlpha(1.0f);               }             });           }         }).start();   }  }         
簡單的使用mBlueBall.animate().alpha(0).y(mScreenHeight / 2).setDuration(1000).start()就能實現動畫~~不過需要SDK11,此后在SDK12,SDK16又分別添加了withStartAction和withEndAction用于在動畫前,和動畫后執行一些操作。當然也可以.setListener(listener)等操作。
使用ObjectAnimator實現上面的變化,我們可以使用:PropertyValueHolder
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,       0f, 1f);   PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 0,       mScreenHeight / 2, 0);   ObjectAnimator.ofPropertyValuesHolder(mBlueBall, pvhX, pvhY).setDuration(1000).start(); 效果與上面一樣。
運行結果:

新聞熱點
疑難解答