前篇給大家講了LayoutAnimation的知識,LayoutAnimation雖能實現(xiàn)ViewGroup的進入動畫,但只能在創(chuàng)建時有效。在創(chuàng)建后,再往里添加控件就不會再有動畫。在API 11后,又添加了兩個能實現(xiàn)在創(chuàng)建后添加控件仍能應(yīng)用動畫的方法,分別是android:animateLayoutChanges屬性和LayoutTransition類。這篇文章就來簡單說一下他們的用法。由于他們的API 等級必須>=11,API等級稍高,且存在較多問題,并不建議讀者使用,本篇只講解具體用法,不做深究.
在API 11之后,Android為了支持ViewGroup類控件,在添加和移除其中控件時自動添加動畫,為我們提供了一個非常簡單的屬性:android:animateLayoutChanges=[true/false],所有派生自ViewGroup的控件都具有此屬性,只要在XML中添加上這個屬性,就能實現(xiàn)添加/刪除其中控件時,帶有默認動畫了。 我們來看下這次的效果圖:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326102726242.gif" alt="" />
然后來看看具體代碼是如何來做的:
<?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做為動態(tài)添加btn的container,注意,我們給它添加了android:animateLayoutChanges="true"也就是說,它內(nèi)部的控件在添加和刪除時,是會帶有默認動畫。
MyActivity的代碼也很簡單,就是在點擊添加按鈕時向其中動態(tài)添加一個btn,在點擊刪除按鈕時,將其中第一個按鈕給刪除。
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]即可實現(xiàn)內(nèi)部控件添加刪除時都加上動畫效果。
下面我們來做下對比,如果把上面LinearLayout中的android:animateLayoutChanges=[true]給去掉的效果是怎樣的?大家來看下原始添加控件是怎樣的,就知道默認動畫效果是什么了。 在沒加android:animateLayoutChanges=true時:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326103137294.gif" alt="" />
可見,在添加和刪除控件時是沒有任何動畫的。經(jīng)過對比就可知道,默認的進入動畫就是向下部控件下移,然后新添控件透明度從0到1顯示出來。默認的退出動畫是控件透明度從1變到0消失,下部控件上移。
源碼在文章底部給出
上面雖然在ViewGroup類控件XML中僅添加一行android:animateLayoutChanges=[true]即可實現(xiàn)內(nèi)部控件添加刪除時都加上動畫效果。但卻只能使用默認動畫效果,而無法自定義動畫。
為了能讓我們自定義動畫,谷歌在API 11時,同時為我們引入了一個類LayoutTransaction。 要使用LayoutTransaction是非常容易的,只需要三步:
第一步:創(chuàng)建實例
[html] view plain copy 在CODE上查看代碼片派生到我的代碼片
LayoutTransaction transitioner = new LayoutTransition();
第二步:創(chuàng)建動畫并設(shè)置
[java] view plain copy 在CODE上查看代碼片派生到我的代碼片
ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);
transitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
第三步:將LayoutTransaction設(shè)置進ViewGroup
[java] view plain copy 在CODE上查看代碼片派生到我的代碼片
linearLayout.setLayoutTransition(mTransitioner);
其中第三步中,在API 11之后,所有派生自ViewGroup類,比如LinearLayout,F(xiàn)rameLayout,RelativeLayout等,都具有一個專門用來設(shè)置LayoutTransition的方法:
[java] view plain copy 在CODE上查看代碼片派生到我的代碼片
public void setLayoutTransition(LayoutTransition transition)
在第二步中,transitioner.setAnimator設(shè)置動畫的函數(shù)聲明為:
[java] view plain copy 在CODE上查看代碼片派生到我的代碼片
public void setAnimator(int transitionType, Animator animator)
其中
第一個參數(shù)int transitionType:表示當(dāng)前應(yīng)用動畫的對象范圍,取值有:
這幾個具體的意義,我們后面會具體來講。
第二個參數(shù)Animator animator:表示當(dāng)前所選范圍的控件所使用的動畫。
我們先來看看LayoutTransition.APPEARING與LayoutTransition.DISAPPEARING分別代表什么意義: 我們先來看效果圖:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326103740646.gif" alt="" />
大家可以看到,在新增一個btn時,這個新增的btn會有一個繞Y軸旋轉(zhuǎn)360度的動畫。這個就是LayoutTransition.APPEARING所對應(yīng)的當(dāng)一個控件出現(xiàn)時所對應(yīng)的動畫。
當(dāng)我們從容器中移除一個控件時,這個被移除的控件會繞Z軸旋轉(zhuǎn)90度后,再消失。這個就是LayoutTransition.DISAPPEARING在一個控件被移除時,此被移除的控件所對應(yīng)的動畫。
這樣大家就理解了,LayoutTransition.APPEARING和LayoutTransition.DISAPPEARING的意義。下面我們就來看看代碼吧。
這個示例也是建立在上個android:animateLayoutChanges屬性所對應(yīng)示例的基礎(chǔ)上的,所以框架部分是一樣的,僅列出代碼,不再多講,只講關(guān)鍵部分。
首先是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在這個容器中消失時觸發(fā)的動畫
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中動態(tài)添加一個控件,在點擊“移除控件”按鈕時,將LinearLayout中第一個控件給移除。
但是非常注意的是我們的LayoutTransition是在OnCreate中設(shè)置的,也就是說是在LinearLayout創(chuàng)建時就給它定義好控件的入場動畫和出場動畫的,定義代碼如下:
mTransitioner = new LayoutTransition();
//入場動畫:view在這個容器中消失時觸發(fā)的動畫
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);
代碼難度不大,也就是我們這節(jié)開始時所講的那三步:
第一步,定義LayoutTransition實例:
mTransitioner = new LayoutTransition();
第二步:創(chuàng)建動畫并設(shè)置
//入場動畫:view在這個容器中消失時觸發(fā)的動畫
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);
分別定義了,當(dāng)一個控件被插入時,這個被插入的控件所使用的動畫:即繞Y軸旋轉(zhuǎn)360度。
ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f);
mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);
然后是當(dāng)一個控件被移除時,這個被移除的控件所使用的動畫:即繞Z軸旋轉(zhuǎn)90度:
ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);
mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
第三步:將LayoutTransaction設(shè)置進ViewGroup
layoutTransitionGroup.setLayoutTransition(mTransitioner);
這段代碼很容易理解,沒什么難度,這里涉及到ObjectAnimator相關(guān)的動畫知識,如果有不理解的同學(xué)請參考
《Animation動畫詳解(七)——ObjectAnimator基本使用》
我們先來看下本例的效果圖,先理解LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING分別是什么意義
http://wiki.jikexueyuan.com/project/android-animation/images/20160326104449420.gif" alt="" />
在這個效果圖中,在添加控件時,除了被添加控件本身的入場動畫以外,其它需要移動位置的控件,在移動位置時,也被添加上了動畫(left點位移動畫),這些除了被添加控件以外的其它需要移動位置的控件組合,所對應(yīng)的動畫就是LayoutTransition.CHANGE_APPEARING 同樣,在移除一個控件時,因為移除了一個控件,而其它所有需要改變位置的控件組合所對應(yīng)的動畫就是LayoutTransition.CHANGE_DISAPPEARING,這里L(fēng)ayoutTransition.CHANGE_DISAPPEARING所對應(yīng)的動畫是 《 Animation動畫詳解(八)——PropertyValuesHolder與Keyframe》的響鈴效果。
我們這里先看看LayoutTransition.CHANGE_APPEARING所對應(yīng)的完整代碼
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在這個容器中消失時觸發(fā)的動畫
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)我們已經(jīng)講過了,下面我們主要看看入場時,其它控件位移動畫的部分:
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);
這里有幾點注意事項:
1、LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必須使用PropertyValuesHolder所構(gòu)造的動畫才會有效果,不然無效!也就是說使用ObjectAnimator構(gòu)造的動畫,在這里是不會有效果的!
2、在構(gòu)造PropertyValuesHolder動畫時,”left”、”top”屬性的變動是必寫的。如果不需要變動,則直接寫為:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);
3、在構(gòu)造PropertyValuesHolder時,所使用的ofInt,ofFloat中的參數(shù)值,第一個值和最后一個值必須相同,不然此屬性所對應(yīng)的的動畫將被放棄,在此屬性值上將不會有效果;
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);
比如,這里ofInt(“l(fā)eft”,0,100,0)第一個值和最后一個值都是0,所以這里會有效果的,如果我們改為ofInt(“l(fā)eft”,0,100);那么由于首尾值不一致,則將被視為無效參數(shù),將不會有效果!
4、在構(gòu)造PropertyValuesHolder時,所使用的ofInt,ofFloat中,如果所有參數(shù)值都相同,也將不會有動畫效果。
比如:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",100,100);
在這條語句中,雖然首尾一致,但由于全程參數(shù)值相同,所以left屬性上的這個動畫會被放棄,在left屬性上也不會應(yīng)用上任何動畫。
看到了吧,坑就是如此多,至于這些都是為什么,我也懶得去研究它的源碼,因為LayoutTransition的問題實在是太!多!了!至于這篇文章嘛,由于這是一個Android 動畫的系列,而LayoutTransition也是其中一員,本著尊重知識的原則,還是給大家講一講,至于應(yīng)用嘛!呵呵,慎用之……
我們上面講了,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);
對應(yīng)動畫效果為:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326104952037.gif" alt="" />
好了,我們下面來看看LayoutTransition.CHANGE_DISAPPEARING的具體實現(xiàn)
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變動的,所有給他們設(shè)置為無效值:(看到了沒,必須設(shè)置的意思就是即使設(shè)置的值是無效的,也要設(shè)置!不然就會由于Left,top屬性沒有設(shè)置而整個PropertyValuesHolder動畫無效,好惡心的用法……大家可以在源碼注掉哪句話,或者把上面的所有無效設(shè)置嘗試一遍,看看效果便知)
PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);
PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);
第二步:用KeyFrame構(gòu)造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的構(gòu)造方法總共有四個:ofInt,ofFloat,ofObject,ofKeyFrame,這些方法的具體用法已經(jīng)在《Animation動畫詳解(八)——PropertyValuesHolder與Keyframe》中已經(jīng)詳細講解,這里就不再贅述,有關(guān)響鈴效果也是從這篇文章中摘出,所以這里也不再講解。
最后一步,設(shè)置LayoutTransition.CHANGE_DISAPPEARING動畫
ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);
mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);
對應(yīng)效果為:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326112810303.gif" alt="" />
所以所有動畫所對應(yīng)的完整代碼如下:
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在這個容器中消失時觸發(fā)的動畫
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);
}
源碼在文章底部給出
(1)、基本設(shè)置 上面我們講了LayoutTransition的setAnimator方法,在LayoutTransition中還有一些其它方法,下面我們來講解下:
/**
* 設(shè)置所有動畫完成所需要的時長
*/
public void setDuration(long duration)
/**
* 針對單個type,設(shè)置動畫時長;
* transitionType取值為:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING
*/
public void setDuration(int transitionType, long duration)
/**
* 針對單個type設(shè)置插值器
* transitionType取值為:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING
*/
public void setInterpolator(int transitionType, TimeInterpolator interpolator)
/**
* 針對單個type設(shè)置動畫延時
* transitionType取值為:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING
*/
public void setStartDelay(int transitionType, long delay)
/**
* 針對單個type設(shè)置,每個子item動畫的時間間隔
*/
public void setStagger(int transitionType, long duration)
除了setStagger以外,如果你把我的Animation系列一路看下來的話,其它這些函數(shù)理解起來只能說so easy,這里就不再舉例了,下面我們講講setStagger用法與效果
我們還回來看看上面的效果圖:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326105519434.gif" alt="" />
在這個效果圖中,當(dāng)插入一個控件時,CHANGE_APPEARING動畫時的所有控件是一起做動畫的,我們需要做動畫的控件,逐個做動畫,而不是一起全部來做動畫,setStagger就是用來設(shè)置單個item間的動畫間隔的。
在上面的基礎(chǔ)上,我們給LayoutTransition.CHANGE_APPEARING添加上每個item間的時間間隔30ms:
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
動畫效果為:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326105646358.gif" alt="" />
明顯可以看出,做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在這個容器中消失時觸發(fā)的動畫
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);
//設(shè)置單個item間的動畫間隔
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
layoutTransitionGroup.setLayoutTransition(mTransitioner);
}
(2)、LayoutTransition設(shè)置監(jiān)聽
LayoutTransition還給提供了一個監(jiān)聽函數(shù):
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開始和結(jié)束時,都會調(diào)用TransitionListener的startTransition和endTransition方法。
在TransitionListener中總共有四個參數(shù):
如果我們給上面的示例中的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());
}
});
看添加動畫時,Log的輸出是怎樣的:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326105939861.gif" alt="" />
對應(yīng)的Log輸出為:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326110116395.png" alt="" />
先看添加第一個控件時:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326110154989.png" alt="" />
在startTransition中,除去transitionType:2的APPEARING所對應(yīng)的動畫以外,在transitionType:0所對應(yīng)的CHANGE_APPEARING時竟然也傳給了LinearLayout控件! 同樣,在插入第二個控件時,CHANGE_APPEARING事件也進行了上傳和監(jiān)聽! 同樣在刪除控件時,CHANGE_DISAPPEARING也是會上傳給父控件的
http://wiki.jikexueyuan.com/project/android-animation/images/20160326110306132.gif" alt="" />
所對應(yīng)的Log如下:
http://wiki.jikexueyuan.com/project/android-animation/images/20160326112202998.png" alt="" />
所以這里的結(jié)論就是:在使用addTransitionListener監(jiān)聽LayoutTransition過程監(jiān)聽時,CHANGE_APPEARING和CHANGE_DISAPPEARING事件都會上傳給父類控件!
源碼在文章底部給出
到這里,這個系列的知識基本就講完了,下一篇就是給大家講講第三方庫nieOldAndroid的用法,做為Android animation動畫系列的結(jié)尾。
源碼內(nèi)容:
1、《BlogAnimateLayoutChanges》:第一部分AnimateLayoutChanges屬性所對應(yīng)的代碼 2、《BlogLayoutTransition》:第二部分LayoutTransition所對應(yīng)的代碼
源碼下載地址:http://download.csdn.net/download/harvic880925/9473049