前篇給你們講了LayoutAnimation的知識,LayoutAnimation雖能實現ViewGroup的進入動畫,但只能在建立時有效。在建立後,再往裏添加控件就不會再有動畫。在API 11後,又添加了兩個能實如今建立後添加控件仍能應用動畫的方法,分別是android:animateLayoutChanges屬性和LayoutTransition類。這篇文章就來簡單說一下他們的用法。因爲他們的API 等級必須>=11,API等級稍高,且存在較多問題,並不建議讀者使用,本篇只講解具體用法,不作深究.html
在API 11以後,Android爲了支持ViewGroup類控件,在添加和移除其中控件時自動添加動畫,爲咱們提供了一個很是簡單的屬性:android:animateLayoutChanges=[true/false],全部派生自ViewGroup的控件都具備此屬性,只要在XML中添加上這個屬性,就能實現添加/刪除其中控件時,帶有默認動畫了。
咱們來看下此次的效果圖:java
而後來看看具體代碼是如何來作的:android
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/add_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="添加控件"/> <Button android:id="@+id/remove_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="移除控件"/> </LinearLayout> <LinearLayout android:id="@+id/layoutTransitionGroup" android:layout_width="match_parent" android:layout_height="wrap_content" android:animateLayoutChanges="true" android:orientation="vertical"/> </LinearLayout>
佈局代碼很簡單,兩個按鈕,最底部是一個LinearLayout作爲動態添加btn的container,注意,咱們給它添加了android:animateLayoutChanges="true"也就是說,它內部的控件在添加和刪除時,是會帶有默認動畫。框架
MyActivity的代碼也很簡單,就是在點擊添加按鈕時向其中動態添加一個btn,在點擊刪除按鈕時,將其中第一個按鈕給刪除。ide
public class MyActivity extends Activity implements View.OnClickListener { private LinearLayout layoutTransitionGroup; private int i = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup); findViewById(R.id.add_btn).setOnClickListener(this); findViewById(R.id.remove_btn).setOnClickListener(this); } private void addButtonView() { i++; Button button = new Button(this); button.setText("button" + i); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); button.setLayoutParams(params); layoutTransitionGroup.addView(button, 0); } private void removeButtonView() { if (i > 0) { layoutTransitionGroup.removeViewAt(0); } i--; } @Override public void onClick(View v) { if (v.getId() == R.id.add_btn) { addButtonView(); } if (v.getId() == R.id.remove_btn) { removeButtonView(); } } }
代碼很簡單就再也不細講了。函數
由上面的效果圖可見,咱們只須要在viewGroup的XML中添加一行代碼android:animateLayoutChanges=[true]便可實現內部控件添加刪除時都加上動畫效果。
下面咱們來作下對比,若是把上面LinearLayout中的android:animateLayoutChanges=[true]給去掉的效果是怎樣的?你們來看下原始添加控件是怎樣的,就知道默認動畫效果是什麼了。
在沒加android:animateLayoutChanges=true時:佈局
可見,在添加和刪除控件時是沒有任何動畫的。通過對比就可知道,默認的進入動畫就是向下部控件下移,而後新添控件透明度從0到1顯示出來。默認的退出動畫是控件透明度從1變到0消失,下部控件上移。 動畫
上面雖然在ViewGroup類控件XML中僅添加一行android:animateLayoutChanges=[true]便可實現內部控件添加刪除時都加上動畫效果。但卻只能使用默認動畫效果,而沒法自定義動畫。
爲了能讓咱們自定義動畫,谷歌在API 11時,同時爲咱們引入了一個類LayoutTransaction。
要使用LayoutTransaction是很是容易的,只須要三步: this
第一步:建立實例spa
LayoutTransaction transitioner = new LayoutTransition();
第二步:建立動畫並設置
ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f); transitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
第三步:將LayoutTransaction設置進ViewGroup
linearLayout.setLayoutTransition(mTransitioner);
其中第三步中,在API 11以後,全部派生自ViewGroup類,好比LinearLayout,FrameLayout,RelativeLayout等,都具備一個專門用來設置LayoutTransition的方法:
public void setLayoutTransition(LayoutTransition transition)
在第二步中,transitioner.setAnimator設置動畫的函數聲明爲:
public void setAnimator(int transitionType, Animator animator)
其中
第一個參數int transitionType:表示當前應用動畫的對象範圍,取值有:
這幾個具體的意義,咱們後面會具體來說。
第二個參數Animator animator:表示當前所選範圍的控件所使用的動畫。
你們能夠看到,在新增一個btn時,這個新增的btn會有一個繞Y軸旋轉360度的動畫。這個就是LayoutTransition.APPEARING所對應的當一個控件出現時所對應的動畫。
當咱們從容器中移除一個控件時,這個被移除的控件會繞Z軸旋轉90度後,再消失。這個就是LayoutTransition.DISAPPEARING在一個控件被移除時,此被移除的控件所對應的動畫。
這樣你們就理解了,LayoutTransition.APPEARING和LayoutTransition.DISAPPEARING的意義。下面咱們就來看看代碼吧。
這個示例也是創建在上個android:animateLayoutChanges屬性所對應示例的基礎上的,因此框架部分是同樣的,僅列出代碼,再也不多講,只講關鍵部分
首先是main.xml佈局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/add_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="添加控件"/> <Button android:id="@+id/remove_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="移除控件"/> </LinearLayout> <LinearLayout android:id="@+id/layoutTransitionGroup" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"/> </LinearLayout>
佈局代碼與上面同樣,但惟一不一樣的是在LinearLayout中沒有android:animateLayoutChanges="true"
而後是在MyActivity中的代碼處理
public class MyActivity extends Activity implements View.OnClickListener{ private LinearLayout layoutTransitionGroup; private LayoutTransition mTransitioner; private int i = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup); findViewById(R.id.add_btn).setOnClickListener(this); findViewById(R.id.remove_btn).setOnClickListener(this); mTransitioner = new LayoutTransition(); //入場動畫:view在這個容器中消失時觸發的動畫 ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f); mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn); //出場動畫:view顯示時的動畫 ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f); mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut); layoutTransitionGroup.setLayoutTransition(mTransitioner); } private void addButtonView() { i++; Button button = new Button(this); button.setText("button" + i); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); button.setLayoutParams(params); layoutTransitionGroup.addView(button, 0); } private void removeButtonView() { if (i > 0) { layoutTransitionGroup.removeViewAt(0); } i--; } @Override public void onClick(View v) { if (v.getId() == R.id.add_btn) { addButtonView(); } if (v.getId() == R.id.remove_btn) { removeButtonView(); } } }
一樣是在點擊「添加控件」按鈕時,向LinearLayout中動態添加一個控件,在點擊「移除控件」按鈕時,將LinearLayout中第一個控件給移除。
可是很是注意的是咱們的LayoutTransition是在OnCreate中設置的,也就是說是在LinearLayout建立時就給它定義好控件的入場動畫和出場動畫的,定義代碼以下:
mTransitioner = new LayoutTransition(); //入場動畫:view在這個容器中消失時觸發的動畫 ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f); mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn); //出場動畫:view顯示時的動畫 ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f); mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut); layoutTransitionGroup.setLayoutTransition(mTransitioner);
代碼難度不大,也就是咱們這節開始時所講的那三步:
第一步,定義LayoutTransition實例:
mTransitioner = new LayoutTransition();
第二步:建立動畫並設置
//入場動畫:view在這個容器中消失時觸發的動畫 ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f); mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn); //出場動畫:view顯示時的動畫 ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f); mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
分別定義了,當一個控件被插入時,這個被插入的控件所使用的動畫:即繞Y軸旋轉360度。
ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f); mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);
而後是當一個控件被移除時,這個被移除的控件所使用的動畫:即繞Z軸旋轉90度:
ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f); mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
第三步:將LayoutTransaction設置進ViewGroup
layoutTransitionGroup.setLayoutTransition(mTransitioner);
這段代碼很容易理解,沒什麼難度,這裏涉及到ObjectAnimator相關的動畫知識,若是有不理解的同窗請參考《Animation動畫詳解(七)——ObjectAnimator基本使用》
咱們先來看下本例的效果圖,先理解LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING分別是什麼意義
在這個效果圖中,在添加控件時,除了被添加控件自己的入場動畫之外,其它須要移動位置的控件,在移動位置時,也被添加上了動畫(left點位移動畫),這些除了被添加控件之外的其它須要移動位置的控件組合,所對應的動畫就是LayoutTransition.CHANGE_APPEARING
一樣,在移除一個控件時,由於移除了一個控件,而其它全部須要改變位置的控件組合所對應的動畫就是LayoutTransition.CHANGE_DISAPPEARING,這裏LayoutTransition.CHANGE_DISAPPEARING所對應的動畫是
《 Animation動畫詳解(八)——PropertyValuesHolder與Keyframe》的響鈴效果。
咱們這裏先看看LayoutTransition.CHANGE_APPEARING所對應的完整代碼
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup); findViewById(R.id.add_btn).setOnClickListener(this); findViewById(R.id.remove_btn).setOnClickListener(this); mTransitioner = new LayoutTransition(); //入場動畫:view在這個容器中消失時觸發的動畫 ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f); mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn); //出場動畫:view顯示時的動畫 ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f); mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut); PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0); PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1); Animator changeAppearAnimator = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhBottom,pvhTop,pvhRight); mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator); layoutTransitionGroup.setLayoutTransition(mTransitioner); }
入場動畫((LayoutTransition.APPEARING)和出場動畫(LayoutTransition.DISAPPEARING)咱們已經講過了,下面咱們主要看看入場時,其它控件位移動畫的部分:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0); PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1); Animator changeAppearAnimator = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhBottom,pvhTop,pvhRight); mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);
這裏有幾點注意事項:
一、LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必須使用PropertyValuesHolder所構造的動畫纔會有效果,否則無效!也就是說使用ObjectAnimator構造的動畫,在這裏是不會有效果的!
二、在構造PropertyValuesHolder動畫時,」left」、」top」屬性的變更是必寫的。若是不須要變更,則直接寫爲:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);
三、在構造PropertyValuesHolder時,所使用的ofInt,ofFloat中的參數值,第一個值和最後一個值必須相同,否則此屬性所對應的的動畫將被放棄,在此屬性值上將不會有效果;
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);
好比,這裏ofInt(「left」,0,100,0)第一個值和最後一個值都是0,因此這裏會有效果的,若是咱們改成ofInt(「left」,0,100);那麼因爲首尾值不一致,則將被視爲無效參數,將不會有效果!
4.在構造PropertyValuesHolder時,所使用的ofInt,ofFloat中,若是全部參數值都相同,也將不會有動畫效果。
好比:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",100,100);
在這條語句中,雖然首尾一致,但因爲全程參數值相同,因此left屬性上的這個動畫會被放棄,在left屬性上也不會應用上任何動畫。
看到了吧,坑就是如此多,至於這些都是爲何,我也懶得去研究它的源碼,由於LayoutTransition的問題實在是太!多!了!至於這篇文章嘛,因爲這是一個Android 動畫的系列,而LayoutTransition也是其中一員,本着尊重知識的原則,仍是給你們講一講,至於應用嘛!呵呵,慎用之……
咱們上面講了,left,top屬性是必須的,下面咱們給他擴展一下,除了給它添加left,top屬性之外,再給它加上scale屬性,讓它同時放大,代碼即:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0); PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1); PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f); Animator changeAppearAnimator = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX); mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);
對應動畫效果爲:
好了,咱們下面來看看LayoutTransition.CHANGE_DISAPPEARING的具體實現
PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0); PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0); Keyframe frame0 = Keyframe.ofFloat(0f, 0); Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f); Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f); Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f); Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f); Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f); Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f); Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f); Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f); Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f); Keyframe frame10 = Keyframe.ofFloat(1, 0); PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10); ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder); mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);
第一步:因爲left,top屬性是必須的,但咱們作響鈴效果時,是不須要Left,top變更的,全部給他們設置爲無效值:(看
到了沒,必須設置的意思就是即便設置的值是無效的,也要設置!否則就會因爲Left,top屬性沒有設置而整個PropertyValuesHolder動畫無效,好惡心的用法……你們能夠在源碼注掉哪句話,或者把上面的全部無效設置嘗試一遍,看看效果便知)
PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);
PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);
第二步:用KeyFrame構造PropertyValuesHolder
Keyframe frame0 = Keyframe.ofFloat(0f, 0); Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f); Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f); Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f); Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f); Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f); Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f); Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f); Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f); Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f); Keyframe frame10 = Keyframe.ofFloat(1, 0); PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);
PropertyValuesHolder的構造方法總共有四個:ofInt,ofFloat,ofObject,ofKeyFrame,這些方法的具體用法已經在《Animation動畫詳解(八)——PropertyValuesHolder與Keyframe》中已經詳細講解,這裏就再也不贅述,有關響鈴效果也是從這篇文章中摘出,因此這裏也再也不講解。
最後一步,設置LayoutTransition.CHANGE_DISAPPEARING動畫
ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder); mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);
對應效果爲:
因此全部動畫所對應的完整代碼以下:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup); findViewById(R.id.add_btn).setOnClickListener(this); findViewById(R.id.remove_btn).setOnClickListener(this); mTransitioner = new LayoutTransition(); //入場動畫:view在這個容器中消失時觸發的動畫 ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f); mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn); //出場動畫:view顯示時的動畫 ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f); mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut); /** * LayoutTransition.CHANGE_APPEARING動畫 */ PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0); PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1); //必須第一個值與最後一值相同纔會有效果,否則沒有效果 PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f); Animator changeAppearAnimator = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX); mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator); /** * LayoutTransition.CHANGE_DISAPPEARING動畫 */ PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0); PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0); Keyframe frame0 = Keyframe.ofFloat(0f, 0); Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f); Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f); Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f); Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f); Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f); Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f); Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f); Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f); Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f); Keyframe frame10 = Keyframe.ofFloat(1, 0); PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10); ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder); mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing); layoutTransitionGroup.setLayoutTransition(mTransitioner); }
上面咱們講了LayoutTransition的setAnimator方法,在LayoutTransition中還有一些其它方法,下面咱們來說解下:
/** * 設置全部動畫完成所須要的時長 */ public void setDuration(long duration) /** * 針對單個type,設置動畫時長; * transitionType取值爲:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING */ public void setDuration(int transitionType, long duration) /** * 針對單個type設置插值器 * transitionType取值爲:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING */ public void setInterpolator(int transitionType, TimeInterpolator interpolator) /** * 針對單個type設置動畫延時 * transitionType取值爲:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING */ public void setStartDelay(int transitionType, long delay) /** * 針對單個type設置,每一個子item動畫的時間間隔 */ public void setStagger(int transitionType, long duration)
除了setStagger之外,若是你把個人Animation系列一路看下來的話,其它這些函數理解起來只能說so easy,這裏就再也不舉例了,下面咱們講講setStagger用法與效果
咱們還回來看看上面的效果圖:
在這個效果圖中,當插入一個控件時,CHANGE_APPEARING動畫時的全部控件是一塊兒作動畫的,咱們須要作動畫的控件,逐個作動畫,而不是一塊兒所有來作動畫,setStagger就是用來設置單個item間的動畫間隔的。
在上面的基礎上,咱們給LayoutTransition.CHANGE_APPEARING添加上每一個item間的時間間隔30ms:
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
動畫效果爲:
明顯能夠看出,作LayoutTransition.CHANGE_APPEARING的控件確實是有間隔的;
完整代碼爲:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup); findViewById(R.id.add_btn).setOnClickListener(this); findViewById(R.id.remove_btn).setOnClickListener(this); mTransitioner = new LayoutTransition(); //入場動畫:view在這個容器中消失時觸發的動畫 ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f); mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn); //出場動畫:view顯示時的動畫 ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f); mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut); /** * LayoutTransition.CHANGE_APPEARING動畫 */ PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0); PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1); //必須第一個值與最後一值相同纔會有效果,否則沒有效果 PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f); Animator changeAppearAnimator = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX); mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator); /** * LayoutTransition.CHANGE_DISAPPEARING動畫 */ PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0); PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0); Keyframe frame0 = Keyframe.ofFloat(0f, 0); Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f); Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f); Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f); Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f); Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f); Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f); Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f); Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f); Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f); Keyframe frame10 = Keyframe.ofFloat(1, 0); PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10); ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder); mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing); //設置單個item間的動畫間隔 mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30); layoutTransitionGroup.setLayoutTransition(mTransitioner); }
LayoutTransition還給提供了一個監聽函數:
public void addTransitionListener(TransitionListener listener) //其中: public interface TransitionListener { public void startTransition(LayoutTransition transition, ViewGroup container,View view, int transitionType); public void endTransition(LayoutTransition transition, ViewGroup container,View view, int transitionType); }
在任何類型的LayoutTransition開始和結束時,都會調用TransitionListener的startTransition和endTransition方法。
在TransitionListener中總共有四個參數:
若是咱們給上面的示例中的mTransitioner添加上addTransitionListener,而後打上log:
mTransitioner.addTransitionListener(new LayoutTransition.TransitionListener() { @Override public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) { Log.d("qijian","start:"+"transitionType:"+transitionType +"count:"+container.getChildCount() + "view:"+view.getClass().getName()); } @Override public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) { Log.d("qijian","end:"+"transitionType:"+transitionType +"count:"+container.getChildCount() + "view:"+view.getClass().getName()); } });
下面是添加一個控件和刪除一個控件的日誌輸出:
首先,各transitionType的取值對應爲:APPEARING = 二、CHANGE_APPEARING = 0、DISAPPEARING = 三、CHANGE_DISAPPEARING = 1
因此在添加控件時,先是start回調,再是end回調;APPEARING事件所對應的View是控件,而CHANGE_APPEARING所對應的控件是容器。刪除控件時,原理相同。
這是由於,在添加控件時,APPEARING事件只針對當前被添加的控件作動畫,因此返回的View是當前被添加的控件。而CHANGE_APPEARING是對容器中全部已存在的控件作動畫,因此返回的View是容器。
本文轉自:自定義控件三部曲之動畫篇(十二)——animateLayoutChanges與LayoutTransition