介紹
AnimatorSet是組合動畫,前面在ObjectAnimator.ofPropertyValuesHolder(),時也可以做到控制多個屬性做動畫,但是.ofPropertyValuesHolder(),僅僅是將多個屬性同時做動畫卻無法靈活控制每個屬性的播放順序秽誊,針對的是一個控件,而AnimatorSet是組合動畫。更側(cè)重的是在多個動畫播放時對動畫的控制(可以控制動畫的順序酥宴,延時,同時可以控制多個控件的動畫等等)您觉。
<font color=#006400 size=6>AnimatorSet</font>
AnimatorSet針對ValueAnimator和ObjectAnimator都是適用的拙寡,但一般而言,我們不會用到ValueAnimator的組合動畫琳水,所以我們僅講解ObjectAnimator下的組合動畫實現(xiàn)肆糕。
主要方法:
- playSequentially :表示所有動畫依次播放
- playTogether :表示所有動畫一起開始。
-
<font color=#006400>playSequentially :</font>
方法參數(shù):
public void playSequentially(Animator... items);
public void playSequentially(List<Animator> items);
第一個是我們最常用的在孝,它的參數(shù)是可變長參數(shù)诚啃,也就是說我們可以傳進去任意多個Animator對象。這些對象的動畫會逐個播放私沮。第二個構(gòu)造函數(shù)始赎,是傳進去一個List< Animator>的列表。原理一樣仔燕,也是逐個去取List中的動畫對象造垛,然后逐個播放。
使用:
·
private void doPlaySequentiallyAnimator() {
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
tv1BgAnimator.setEvaluator(new ArgbEvaluator());
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 300, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 300, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(tv1BgAnimator, tv1TranslateY, tv2TranslateY);
animatorSet.setDuration(1000);
animatorSet.start();
}
當(dāng)按鈕被點擊時執(zhí)行doPlaySequentiallyAnimator()方法涨享。效果如下:
這就是playSequentially的效果筋搏,即逐個播放動畫,一個動畫結(jié)束后厕隧,播放下一個動畫奔脐,播放的順序就是傳入動畫的先后順序俄周。(這里也可以看出AnimatorSet是針對于動畫,并不管你在動畫是在哪個控件或是幾個控件髓迎,這就與.ofPropertyValuesHolder()不同)
-
<font color=#006400>playTogether :</font>
playTogether表示將所有動畫一起播放 峦朗。
public void playTogether(Animator... items);
public void playTogether(Collection<Animator> items);
參數(shù)含義與上面一致。
代碼:
animatorSet.playTogether(tv1BgAnimator, tv1TranslateY, tv2TranslateY);
其他代碼去上面一致.效果:
此時三個動畫一起播放排龄。
-
<font color=#006400>playSequentially,playTogether真正意義 :</font>
- <font color=#DC143C>playTogether :</font> 只是一個時間點上的一起開始波势,對于開始后,各個動畫怎么操作就是他們自己的事了橄维,至于各個動畫結(jié)不結(jié)束也是他們自已的事了尺铣。
- <font color=#DC143C>playSequentially : </font> 意義是把激活一個動畫之后,動畫之后的操作就是動畫自己來負責(zé)了争舞,這個動畫結(jié)束之后凛忿,再激活下一個動畫。如果上一個動畫沒有結(jié)束竞川,那下一個動畫就永遠也不會被激活店溢。
首先用playTogether來看個例子:
將tv1TranslateY開始延遲2000毫秒開始,并設(shè)為無限循環(huán)委乌。tv2TranslateY設(shè)為開始延遲2000毫秒床牧。而tv1BgAnimator則是沒有任何設(shè)置,所以是默認直接開始遭贸。
從這個例子中也可以看到戈咳,playTogether只是負責(zé)在同一時間點一起開始,對于開始后壕吹,各個動畫怎么操作就是他們自己的事了除秀,至于各個動畫結(jié)不結(jié)束也是他們自已的事了。
將播放改成playSequentially順序播放動畫:
·
private void doPlaySequentiallyAnimator2() {
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
tv1BgAnimator.setEvaluator(new ArgbEvaluator());
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
tv1TranslateY.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(tv1BgAnimator, tv1TranslateY, tv2TranslateY);
animatorSet.setDuration(2000);
animatorSet.start();
}
效果:
tv1BgAnimator顏色改變后移動算利,并設(shè)置成無限循環(huán)册踩。那么tv2TranslateY永遠無法得到執(zhí)行。
總結(jié):
<font color=#006400>
- 第一:playTogether和playSequentially在激活動畫后效拭,控件的動畫情況與它們無關(guān)暂吉,他們只負責(zé)定時激活控件動畫。
- 第二:playSequentially只有上一個控件做完動畫以后缎患,才會激活下一個控件的動畫慕的,如果上一控件的動畫是無限循環(huán),那下一個控件就別再指望能做動畫了挤渔。
</font>
AnimatorSet.Builder-自由設(shè)置動畫順序
上面兩種播放方法只能一起播放或者順序播放肮街,無法指定某一個動畫的播放順序,如果想ABC三個動畫想指定C先播放就要用到AnimatorSet.Builder判导。
AnimatorSet.Builder可以更加靈活設(shè)置動畫播放的先后順序嫉父。
- <font color=#006400>AnimatorSet.Builder :</font>
//調(diào)用AnimatorSet中的play方法是獲取AnimatorSet.Builder對象的唯一途徑
//表示要播放哪個動畫
public Builder play(Animator anim)
- <font color=#006400>更多方法 :</font>
//和前面動畫一起執(zhí)行
public Builder with(Animator anim)
//執(zhí)行前面的動畫后才執(zhí)行該動畫
public Builder before(Animator anim)
//執(zhí)行先執(zhí)行這個動畫再執(zhí)行前面動畫
public Builder after(Animator anim)
//延遲n毫秒之后執(zhí)行動畫
public Builder after(long delay)
<font color=#DC143C>注意: play(Animator anim)表示當(dāng)前在播放哪個動畫沛硅,另外的with(Animator anim)、before(Animator anim)绕辖、after(Animator anim)都是以play中的當(dāng)前所播放的動畫為基準的</font>摇肌。
例如: 當(dāng)play(playAnim)與before(beforeAnim)共用,則表示在播放beforeAnim之前仪际,先播放playAnim動畫围小;同樣,當(dāng)play(playAnim)與after(afterAnim)共用時树碱,則表示在播放afterAnim動畫之后肯适,再播放playAnim動畫。
- <font color=#006400>使用 :</font>
方式一:使用builder對象逐個添加動畫
AnimatorSet.Builder builder = animatorSet.play(tv1TranslateY);
builder.with(tv2TranslateY);
builder.after(tv1BgAnimator);
方式二:串行方式
animatorSet.play(tv1TranslateY).with(tv2TranslateY).after(tv1BgAnimator);
如下:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv1TranslateY).with(tv2TranslateY).after(tv1BgAnimator);
animatorSet.setDuration(2000);
animatorSet.start();
表示在tv1顏色變化后成榜,兩個控件一同開始位移動畫:
AnimatorSet監(jiān)聽器
因為ValueAnimator和AnimatorSet都派生自Animator類疹娶,而AnimatorListener是Animator類中的函數(shù)。所以都是使用相同的監(jiān)聽:
/**
* 監(jiān)聽器二:監(jiān)聽動畫變化時四個狀態(tài)
*/
public static interface AnimatorListener {
/**
* 當(dāng)AnimatorSet開始時調(diào)用
*/
void onAnimationStart(Animator animation);
/**
* 當(dāng)AnimatorSet結(jié)束時調(diào)用
*/
void onAnimationEnd(Animator animation);
/**
* 當(dāng)AnimatorSet被取消時調(diào)用
*/
void onAnimationCancel(Animator animation);
/**
* 當(dāng)AnimatorSet重復(fù)時調(diào)用伦连,由于AnimatorSet沒有設(shè)置repeat的函數(shù),所以這個方法永遠不會被調(diào)用
*/
void onAnimationRepeat(Animator animation);
}
//添加方法為:public void addListener(AnimatorListener listener)
/**
* 監(jiān)聽器三:監(jiān)聽動畫暫停與重新開始
*/
public static interface AnimatorPauseListener {
void onAnimationPause(Animator animation);
void onAnimationResume(Animator animation);
}
//添加方法為:public void addPasueListener(AnimatorPauseListener listener)
同時我們也可以傳入AnimatorListenerAdapter監(jiān)聽器钳垮,他是一個抽象方法惑淳,里面實現(xiàn)了Animator.AnimatorListener,Animator.AnimatorPauseListener接口,這樣我們可以只實現(xiàn)我們需要的方法饺窿。這里我全部實現(xiàn)因為為了打印看出效果:
雖然我們的tv2TranslateY動畫在無限循環(huán)歧焦,但Log中沒有打印出對應(yīng)的repeat的日志,從日志中也可以看出肚医,AnimatorSet的監(jiān)聽函數(shù)也只是用來監(jiān)聽AnimatorSet的狀態(tài)的绢馍,與其中的動畫無關(guān);
總結(jié):
<font color=#006400>
- AnimatorSet的監(jiān)聽函數(shù)也只是用來監(jiān)聽AnimatorSet的狀態(tài)的肠套,與其中的動畫無關(guān)舰涌;
- AnimatorSet中沒有設(shè)置循環(huán)的函數(shù),所以AnimatorSet監(jiān)聽器中永遠無法運行到onAnimationRepeat()中你稚!
</font>
AnimatorSet設(shè)置與單個動畫屬性沖突時
- <font color=#006400>常見沖突函數(shù) </font>
//設(shè)置單次動畫時長
public AnimatorSet setDuration(long duration);
//設(shè)置加速器
public void setInterpolator(TimeInterpolator interpolator)
//設(shè)置ObjectAnimator動畫目標控件
public void setTarget(Object target)
這幾個函數(shù)在ObjectAnimator也存在瓷耙,當(dāng)單個動畫設(shè)置上面的屬性,同時組合動畫AnimatorSet也設(shè)置了相同的屬性刁赖。則遵循下面的規(guī)則:
<font color=#006400>在AnimatorSet中設(shè)置以后搁痛,會覆蓋單個ObjectAnimator中的設(shè)置;即如果AnimatorSet中沒有設(shè)置宇弛,那么就以O(shè)bjectAnimator中的設(shè)置為準鸡典。如果AnimatorSet中設(shè)置以后,ObjectAnimator中的設(shè)置就會無效枪芒。
</font>
例如:
<font color=#DC143C>
- 當(dāng)單個動畫(ObjectAnimator)與組合動畫(AnimatorSet)同時設(shè)置setDuration(long duration)動畫時長彻况,那么所有單個動畫設(shè)置的時長失效谁尸。如果組合動畫(AnimatorSet)沒有設(shè)置setDuration(long duration)動畫時長,那么會每個動畫會根據(jù)自己的時長做動畫疗垛。
- 當(dāng)單個動畫(ObjectAnimator)與組合動畫(AnimatorSet)同時設(shè)置setInterpolator症汹,那么所有單個動畫設(shè)置的加速器失效。如果組合動畫(AnimatorSet)沒有設(shè)置加速器贷腕,那么會每個動畫會根據(jù)自己的加速器做動畫背镇。
</font>
如下:
·
private void doPlaySequentiallyAnimator4() {
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
tv1TranslateY.setDuration(50000000);
tv1TranslateY.setInterpolator(new BounceInterpolator());
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
tv2TranslateY.setDuration(5000);
tv2TranslateY.setInterpolator(new AccelerateDecelerateInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(2000);
animatorSet.play(tv2TranslateY).with(tv1TranslateY);
animatorSet.start();
}
效果:
此時tv1TranslateY與tv2TranslateY都設(shè)置了時長同時AnimatorSet也設(shè)置了時長,發(fā)現(xiàn)只有animatorSet.setDuration(2000);生效泽裳,由于animatorSet沒有設(shè)置加速器瞒斩,所有動畫執(zhí)行各自的加速器。
<font color=#DC143C>
- AnimatorSet.setTarget()的作用就是將動畫的目標統(tǒng)一設(shè)置為當(dāng)前控件涮总,AnimatorSet中的所有動畫都將作用在所設(shè)置的target控件上
</font>
如下:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(tv1BgAnimator,tv2TranslateY);
animatorSet.setDuration(2000);
animatorSet.setTarget(mTv2);
animatorSet.start();
setStartDelay(long startDelay)
//設(shè)置延時開始動畫時長
public void setStartDelay(long startDelay)
當(dāng)AnimatorSet所擁有的函數(shù)與單個動畫所擁有的函數(shù)沖突時胸囱,就以AnimatorSet設(shè)置為準。但唯一的例外就是setStartDelay瀑梗。
setStartDelay函數(shù)不會覆蓋單個動畫的延時烹笔,而且僅針對性的延長AnimatorSet的激活時間,單個動畫的所設(shè)置的setStartDelay仍對單個動畫起作用抛丽。
遵循原則:
<font color=#DC143C>
- AnimatorSet的延時是僅針對性的延長AnimatorSet激活時間的谤职,對單個動畫的延時設(shè)置沒有影響。
- AnimatorSet真正激活延時 = AnimatorSet.startDelay+第一個動畫.startDelay
- 在AnimatorSet激活之后亿鲜,第一個動畫絕對是會開始運行的允蜈,后面的動畫則根據(jù)自己是否延時自行處理。
</font>
<font color=#006400 size=6>XML實現(xiàn)屬性動畫</font>
ValueAnimator蒿柳、ObjectAnimator和AnimatorSet屬性動畫也可以在SML中設(shè)置饶套。在res/animator/目錄下創(chuàng)建XML屬性動畫詳細可以參照
屬性動畫官方文檔
下面只記錄簡單實用:
- <font color=#006400>Animator(ValueAnimator):</font>
XML標簽含義:
<animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]
android:interpolator=["@android:interpolator/XXX"]/>
- android:duration:每次動畫播放的時長
- android:valueFrom:初始動化值;取值范圍為float,int和color垒探,如果取值為float對應(yīng)的值樣式應(yīng)該為89.0妓蛮,取值為Int時,對應(yīng)的值樣式為:89;當(dāng)取值為clolor時圾叼,對應(yīng)的值樣式為 #333333;
- android:valueTo:動畫結(jié)束值仔引;取值范圍同樣是float,int和color這三種類型的值;
- android:startOffset:動畫激活延時褐奥;對應(yīng)代碼中的startDelay(long delay)函數(shù)咖耘;
- android:repeatCount:動畫重復(fù)次數(shù)
- android:repeatMode:動畫重復(fù)模式,取值為repeat和reverse撬码;repeat表示正序重播儿倒,reverse表示倒序重播
- android:valueType:表示參數(shù)值類型,取值為intType和floatType;與android:valueFrom夫否、android:valueTo相對應(yīng)彻犁。如果這里的取值為intType,那么android:valueFrom凰慈、android:valueTo的值也就要對應(yīng)的是int類型的數(shù)值汞幢。如果這里的數(shù)值是floatType,那么android:valueFrom微谓、android:valueTo的值也要對應(yīng)的設(shè)置為float類型的值森篷。非常注意的是,如果android:valueFrom豺型、android:valueTo的值設(shè)置為color類型的值仲智,那么不需要設(shè)置這個參數(shù);
- android:interpolator:設(shè)置加速器姻氨;有關(guān)系統(tǒng)加速器所對應(yīng)的xml值對照表如下:
XML:
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:anim/bounce_interpolator"
android:valueFrom="0"
android:valueType="intType"
android:valueTo="300">
</animator>
代碼:
ValueAnimator valueAnimator= (ValueAnimator) AnimatorInflater.loadAnimator(this,R.animator.animator);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int value= (int) valueAnimator.getAnimatedValue();
tv_text.layout(value,value,tv_text.getWidth()+value,tv_text.getHeight()+value);
}
});
valueAnimator.start();
效果:
- <font color=#006400>objectAnimator(ObjectAnimator):</font>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]
android:interpolator=["@android:interpolator/XXX"]/>
參數(shù):
- android:propertyName:對應(yīng)屬性名钓辆,即ObjectAnimator所需要操作的屬性名。
其它字段的意義與animator的意義與取值是一樣的肴焊,下面再重新列舉一下前联。 - android:duration:每次動畫播放的時長
- android:valueFrom:初始動化值;取值范圍為float,int和color娶眷;
- android:valueTo:動畫結(jié)束值似嗤;取值范圍同樣是float,int和color這三種類型的值;
- android:startOffset:動畫激活延時茂浮;對應(yīng)代碼中的startDelay(long delay)函數(shù);
- android:repeatCount:動畫重復(fù)次數(shù)
- android:repeatMode:動畫重復(fù)模式壳咕,取值為repeat和reverse席揽;repeat表示正序重播,reverse表示倒序重播
- android:valueType:表示參數(shù)值類型谓厘,取值為intType和floatType幌羞;與android:valueFrom、android:valueTo相對應(yīng)竟稳。如果這里的取值為intType属桦,那么android:valueFrom、android:valueTo的值也就要對應(yīng)的是int類型的數(shù)值他爸。如果這里的數(shù)值是floatType聂宾,那么android:valueFrom、android:valueTo的值也要對應(yīng)的設(shè)置為float類型的值诊笤。非常注意的是系谐,如果android:valueFrom、android:valueTo的值設(shè)置為color類型的值,那么不需要設(shè)置這個參數(shù)纪他;
- android:interpolator:設(shè)置加速器鄙煤;
XML:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="TranslationY"
android:duration="2000"
android:valueFrom="0.0"
android:valueTo="400.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:valueType="floatType"
android:repeatCount="1"
android:repeatMode="reverse"
android:startOffset="2000"
>
</objectAnimator>
代碼:
ObjectAnimator objectAnimator= (ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.objectanimator);
objectAnimator.setTarget(tv_text);
objectAnimator.start();
效果:
- <font color=#006400>ObjectAnimator設(shè)置背景顏色:</font>
XML:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="BackgroundColor"
android:duration="5000"
android:valueFrom="#ffff00ff"
android:valueTo="#ffffff00"/>
代碼:
ObjectAnimator objectAnimator= (ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.animatorcolor);
objectAnimator.setTarget(mTv1);
objectAnimator.start();
效果:
-
<font color=#006400>Set(AnimatorSet):</font>
XML:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueFrom="0"
android:valueTo="400"
android:valueType="floatType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType"/>
</set>
<!--這里有兩個objectAnimator動畫,一個改變值x坐標茶袒,一個改變值y坐標梯刚;取值分別為0-400和0-300;然后在代碼中加載-->
代碼:
ObjectAnimator objectAnimator= (ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.animatorcolor);
objectAnimator.setEvaluator(new ArgbEvaluator());
objectAnimator.setTarget(mTv1);
objectAnimator.start();
效果:
更多動畫
- LayoutAnimation : viewGroup添加進入統(tǒng)一動畫的
- gridLayoutAnimation : grideView添加進入動畫的
- android:animateLayoutChanges屬性 : 在API 11之后薪寓,Android為了支持ViewGroup類控件亡资,在添加和移除其中控件時自動添加動畫,為我們提供了一個非常簡單的屬性:android:animateLayoutChanges=[true/false],所有派生自ViewGroup的控件都具有此屬性预愤,只要在XML中添加上這個屬性沟于,就能實現(xiàn)添加/刪除其中控件時,帶有默認動畫了植康。
- LayoutTransaction 對animateLayoutChanges屬性的擴展旷太,可以使用自定義刪除/添加動畫。
結(jié)語
到此動畫部分到此結(jié)束销睁。后期根據(jù)自身的理解如果學(xué)習(xí)到了新得關(guān)于動畫的知識會繼續(xù)記錄動畫相關(guān)的知識點供璧。這是本人的學(xué)習(xí)筆記。十分感謝啟航大神冻记。也希望大家多多支持睡毒。下篇文章將會講解Acitvity啟動布局的加載。
感謝
站在巨人的肩膀上可以讓我們看的更遠冗栗。
Android自定義控件三部曲文章