Android中的動(dòng)畫主要有幀動(dòng)畫琉用、補(bǔ)間動(dòng)畫堕绩、屬性動(dòng)畫(3.0之后出現(xiàn)),此處按照官方將其分為兩大類記錄邑时。他們之間的不一樣的地方奴紧,正如官方對(duì)屬性動(dòng)畫所描述的“you can animate any porperty fo any object(Views and non-Views) and the object itself is actually modified”,View Animation所能做的動(dòng)畫有限晶丘,并且控件本身可能和它的視覺(jué)效果不一致以至于你需要更多的邏輯處理黍氮。但如果View Animation已經(jīng)滿足你的需要了,那就用吧浅浮。
內(nèi)容摘要
- 視覺(jué)動(dòng)畫的使用滤钱。(幀動(dòng)畫、補(bǔ)間動(dòng)畫)
- 屬性動(dòng)畫的使用及原理脑题。(涉及插值器件缸、估值器、關(guān)鍵幀等)
- 布局動(dòng)畫叔遂。(不常用他炊,只簡(jiǎn)單提一下)
- 轉(zhuǎn)場(chǎng)動(dòng)畫争剿。(Activity和Fragment)
- API使用。(包括揭露效果和水波紋動(dòng)畫)
一痊末、View Animation / 視覺(jué)效果的動(dòng)態(tài)改變
官方建議寫為XML以使提高可讀性和復(fù)用性蚕苇,并方便替換。
注意:被施加動(dòng)畫的View不會(huì)調(diào)整自身大小來(lái)適應(yīng)動(dòng)畫變化凿叠,但是動(dòng)畫可以繪制到View邊界之外涩笤。
Frame animation幀動(dòng)畫(官方文檔有一處小錯(cuò)誤)
XML文件放在 res/drawable/xxx.xml
定義在XML文件里,代碼引用設(shè)為View背景盒件,再使用getBackground()獲取到之后強(qiáng)轉(zhuǎn)為AnimationDrawable并調(diào)用start()方法即可蹬碧。
詳細(xì)屬性值:
- 根節(jié)點(diǎn)必須為
<animation-list>
,一個(gè)屬性炒刁。- android:oneshot屬性可設(shè)置是否只播放一次恩沽,默認(rèn)為false,循環(huán)播放翔始。
- 子節(jié)點(diǎn)只有一個(gè)
<item>
罗心,表示一幀。 兩個(gè)屬性城瞎。- android:drawable設(shè)置該幀的圖片
- android:duration設(shè)置該幀的播放時(shí)長(zhǎng)庆揩,單位ms狡刘。
Tween animation補(bǔ)間動(dòng)畫
XML文件放在 res/anim/xxx.xml
文件必須只包含一個(gè)根節(jié)點(diǎn)淀歇,<alpha>
, <scale>
, <translate>
, <rotate>
, or <set>
安皱,子標(biāo)簽也可以繼續(xù)使用 <set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
<!--插值器-->
android:interpolator="@[package:]anim/interpolator_resource"
<!--是否為子元素共享插值器-->
android:shareInterpolator=["true" | "false"]
<!--動(dòng)畫結(jié)束后保持在什么狀態(tài),after為結(jié)束時(shí)的狀態(tài)认然,before沒(méi)發(fā)現(xiàn)什么變化补憾。另外,只能設(shè)置在根標(biāo)簽-->
android:fillAfter=["true" | "false"]
android:fillBefore= ["true" | "false"]
<!--動(dòng)畫時(shí)長(zhǎng)卷员,所以標(biāo)簽都可以設(shè)置盈匾。但父標(biāo)簽有,子標(biāo)簽的就不會(huì)生效-->
android:duration="ms"
<!--重復(fù)模式毕骡,reverse為倒著播放一遍-->
android:repeatMode=["restart" | "reverse"]
<!--動(dòng)畫延遲開(kāi)始時(shí)間-->
android:startOffset="ms">
<alpha
<!--0.0透明削饵,1.0不透明-->
android:fromAlpha="float"
android:toAlpha="float" />
<scale
<!--1.0無(wú)變化-->
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
<!--縮放時(shí)該坐標(biāo)保持固定-->
android:pivotX="float"
android:pivotY="float" />
<translate
<!--具體數(shù)值指像素,加%指相對(duì)于自身未巫,加%p指相對(duì)于父控件-->
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
<!--度數(shù)-->
android:fromDegrees="float"
android:toDegrees="float"
<!--中心點(diǎn)坐標(biāo)窿撬。相對(duì)于控件左邊,具體數(shù)值指像素叙凡,加%指相對(duì)于自身劈伴,加%p指相對(duì)于父控件 -->
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>
使用時(shí)
Animation mAnimation=AnimationUtils.loadAnimation(this,R.anim.xxx);
//mView.startAnimation(mAnimation);
mView.setAnimation(mAnimation);
mAnimation.start();
//添加監(jiān)聽(tīng)器
mAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//動(dòng)畫開(kāi)始
}
@Override
public void onAnimationEnd(Animation animation) {
//動(dòng)畫結(jié)束
}
@Override
public void onAnimationRepeat(Animation animation) {
//動(dòng)畫重復(fù)
}
});
插值器
系統(tǒng)提供的,xml中使用@android:anim/xxxx
- AccelerateDecelerateInterpolator 握爷,加速減速插值器跛璧,中間速度最快
- AccelerateInterpolator严里,加速插值器
- AnticipateInterpolator,預(yù)備插值器追城,先向后刹碾,再向前加速。
- AnticipateOvershootInterpolator座柱,預(yù)備超出迷帜。先向后,到動(dòng)畫最后會(huì)超出一段再回到該處于的狀態(tài)
- BounceInterpolator色洞,彈性插值器戏锹。最后會(huì)有一個(gè)反復(fù)的效果
- CycleInterpolator,循環(huán)锋玲,對(duì)動(dòng)畫效果做一個(gè)正弦函數(shù)景用,0到1到0到-1到0
- DecelerateInterpolator涵叮,減速
- LinearInterpolator惭蹂,線性,速率不變
- OvershootInterpolator割粮,結(jié)束時(shí)多向前一定的值再回到原來(lái)狀態(tài)
自定義插值器盾碗,放置在res/anim/xxx.xml,屬性值不做特別說(shuō)明則都是float類型舀瓢。
-
<accelerateInterpolator>
android:factor廷雅,加速度值,默認(rèn)為1 -
<anticipateInterpolator>
android:tension京髓,張力值航缀,默認(rèn)為2 -
<anticipateOvershootInterpolator>
android:tension,張力值堰怨,默認(rèn)2芥玉;android:extraTension,多少倍的張力备图,默認(rèn)1.5 -
<cycleInterpolator>
android:cycles灿巧,integer,多少周揽涮,默認(rèn)1 -
<decelerateInterpolator>
android:factor抠藕,減速度值,默認(rèn)1 -
<overshootInterpolator>
android:tension蒋困,張力值盾似,默認(rèn)2
如:res/anim/my_overshoot_interpolator.xml
<?xml version="1.0" encoding="utf-8"?>
<overshootInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:tension="7.0"
/>
二、Property Animation 屬性動(dòng)畫/屬性的動(dòng)態(tài)改變
每10ms(具體值根據(jù)運(yùn)行環(huán)境有所不同)根據(jù)規(guī)則(插值器和估值器)設(shè)置一次屬性
結(jié)合場(chǎng)景1和場(chǎng)景2分析原理:
- 需要指定起始值(x=0)门粪、終值(x=40)喊积、時(shí)長(zhǎng)(40ms),并調(diào)用start()開(kāi)始動(dòng)畫玄妈。
- 在動(dòng)畫的執(zhí)行過(guò)程中乾吻,ValueAnimator會(huì)基于動(dòng)畫已經(jīng)運(yùn)行時(shí)間和總時(shí)間來(lái)計(jì)算出一個(gè)0-1的值,稱為elapsed fraction拟蜻,如場(chǎng)景中t=10ms的時(shí)候該值為 10/40=0.25绎签。
- 調(diào)用當(dāng)前設(shè)置的TimeInterpolator(該類為所有具體的插值器的最終父類)計(jì)算interpolated fraction的值,該值依據(jù)elapsed fraction和插值器計(jì)算酝锅,如場(chǎng)景二因?yàn)槭羌訙p速插值器所以在t=10ms時(shí)interpolated fraction的值為0.15诡必,而場(chǎng)景一由于是線性插值器原因,該時(shí)刻的值為0.25搔扁,和elapsed fraction保持一致
- 之后會(huì)調(diào)用合適的TypeEvaluator去計(jì)算屬性當(dāng)前時(shí)刻的值爸舒,該值根據(jù)interpolated fraction、起始值和結(jié)束值稿蹲。如場(chǎng)景二中t=10ms時(shí)扭勉,屬性x的值為0.15*(40-0)=6
XML位置:res/animator/xxx.xml
xml文件根標(biāo)簽必須是 <set>
, <objectAnimator>
, or <animator>
,同樣苛聘,<set>
標(biāo)簽可以嵌套<set>
<set
<!--同時(shí)執(zhí)行|順序執(zhí)行-->
android:ordering=["together" | "sequentially"]>
<objectAnimator
<!--屬性名涂炎,必須。施加動(dòng)畫的object必須有這個(gè)屬性-->
android:propertyName="string"
android:duration="int"
<!--動(dòng)畫屬性起始值设哗,不指定的話會(huì)從從屬性的getXX()方法獲取-->
android:valueFrom="float | int | color(6位16進(jìn)制如#222222唱捣,后同)"
<!--必須-->
android:valueTo="float | int | color"
android:startOffset="int"
<!--重復(fù)次數(shù),-1無(wú)限网梢,1意思為運(yùn)行2次震缭,0表示不重復(fù)-->
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
<!--指定值的類型-->
android:valueType=["intType" | "floatType"(default)]/>
<!--對(duì)應(yīng)ValueAnimator-->
<animator
android:duration="int"
<!--From和To在該標(biāo)簽下都是必須,F(xiàn)rom不會(huì)自指定-->
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<set>
...
</set>
</set>
如 res/animator/property_animator.xml
:
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
代碼中使用:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(comtext,
R.animator.property_animator);
set.setTarget(myObject);
set.start();
//另外AnimatorSet還有多種使用方法,靈活使用playTogether()澎粟、play()蛀序、with()、before()活烙、after()來(lái)實(shí)現(xiàn)復(fù)雜的效果
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
監(jiān)聽(tīng)器
- Animator.AnimatorListener()徐裸,可以使用AnimatorListenerAdapter()來(lái)有選擇的實(shí)現(xiàn)某些方法。
- onAnimationStart()啸盏,動(dòng)畫開(kāi)始
- onAnimationEnd()重贺,動(dòng)畫結(jié)束
- onAnimationRepeat(),動(dòng)畫重復(fù)
- onAnimationCancel(),動(dòng)畫取消
- ValueAnimator.AnimatorUpdateListener()
- onAnimationUpdate()气笙,通過(guò)animation.getAnimatedValue()來(lái)獲取值的變化次企,值為上邊第四步的值,即結(jié)合了插值器潜圃、起始值和終值計(jì)算出來(lái)的值缸棵。
容器動(dòng)畫LayoutTransition
LayoutTransition mTransitioner=new LayoutTransition();
cotainerView.setLayoutTransition( mTransitioner )谭期;
ObjectAnimator animator = ObjectAnimator.ofFloat(null,"xxx").setDuration(mTransitioner.getDuration(LayoutTransition.APPEARING));
mTransitioner.setAnimator(LayoutTransition.APPEARING,animator);
//LayoutTransition.APPEARING為出現(xiàn)堵第,另外還有DISAPEARINHG消失,CHANGE_APPEARING隧出,CHANGE_DISAPPEARING別的項(xiàng)目從容器中消失或者出現(xiàn)而發(fā)生改變的項(xiàng)目的動(dòng)畫踏志。
需要使用系統(tǒng)默認(rèn)的ViewGroup布局改變的動(dòng)畫,只需要在設(shè)置android.animateLayoutchanges
為true即可胀瞪。
使用Interpolators
基本使用不再多說(shuō)针余,系統(tǒng)給了很多具體的實(shí)現(xiàn),可以結(jié)合起來(lái)自由使用凄诞。在此只分析其代碼的實(shí)現(xiàn)圆雁,打開(kāi)自定義的思路。
在插值器必須實(shí)現(xiàn)的接口TimeInterpolator里只有一個(gè)抽象方法 :
float getInterpolation(float input);
- 接收參數(shù) input幔摸,即之前所說(shuō)的 elapsed fraction 摸柄,代表整個(gè)動(dòng)畫的執(zhí)行過(guò)程颤练。舉例既忆,一個(gè)時(shí)長(zhǎng)2000ms的動(dòng)畫,在開(kāi)始時(shí)參數(shù)input的值為0嗦玖,執(zhí)行500ms時(shí)患雇,input=500/2000=0.25,并最終等于1宇挫。該值只與動(dòng)畫的執(zhí)行時(shí)間有關(guān)苛吱,并勻速由0到1,與插值器等其他元素?zé)o關(guān)器瘪。
- 返回值翠储,即之前所說(shuō)的 interpolated fraction ,實(shí)際的進(jìn)度值橡疼。如線性插值器直接返回的input參數(shù)的值援所;而其他插值器都是經(jīng)過(guò)各種計(jì)算實(shí)現(xiàn)的效果。保證初值和終值為0和1即可欣除,該值可以大于1(超過(guò)目標(biāo)進(jìn)度)住拭,也可以小于0(小于開(kāi)始位置)。
所以,在自定義插值器的時(shí)候滔岳,可以簡(jiǎn)單的實(shí)現(xiàn)TimeInterpolator杠娱,并實(shí)現(xiàn)其getInterpolation()方法,寫上自己的邏輯即可谱煤。
使用TypeEvaluator
有相應(yīng)的setEvaluator方法摊求,系統(tǒng)有IntEvaluator、FloatEvaluator刘离、ArgbEvaluator三種實(shí)現(xiàn)睹簇,最后一種用于color。高Api有其他具體實(shí)現(xiàn)此處暫且不提寥闪。
我們知道太惠,通過(guò)AnimateUpdateListener我們得到的是屬性當(dāng)前具體的值,而不是0-1的小數(shù)疲憋。這個(gè)具體的值就是通過(guò)Evaluator來(lái)得到的凿渊。
注意:監(jiān)聽(tīng)中,animation.getAnimatedValue()方法的返回值是object類型缚柳,也就是說(shuō)可以返回任何我們想要的數(shù)值類型埃脏。首先,系統(tǒng)已經(jīng)實(shí)現(xiàn)的Evaluator有int秋忙、float彩掐、argb,三種灰追。通過(guò)分析堵幽,我們也可以自定義自己的Evaluator。
在Evaluator必須實(shí)現(xiàn)的接口TypeEvaluator里也是只有一個(gè)抽象方法:
public interface TypeEvaluator<T> {
public T evaluate(float fraction, T startValue, T endValue);
}
- 泛型弹澎,IntEvaluator的泛型是Integer朴下,F(xiàn)loatEvaluator是Number,而ArgbEvaluator由于最后返回的是ARGB色苦蒿,為4個(gè)int值殴胧,泛型為Object類型沒(méi)有做特殊規(guī)定。我們可以規(guī)定Char佩迟、String团滥、甚至是自己的Bean類如果有必要的話。
- evaluate()方法报强,第一個(gè)參數(shù)為插值器getInterpolation()的返回值灸姊,即 interpolated fraction ,第二個(gè)參數(shù)為我們?cè)O(shè)定的初值躺涝,第三個(gè)參數(shù)為我們?cè)O(shè)定的終值厨钻。如我們?cè)O(shè)置ofInt(100,400)扼雏,則對(duì)應(yīng)的初值和終值即為100、400夯膀。
- 返回值诗充,Int和float都是(初值+fraction*(終值-初值)),很容易理解诱建。而Argb也是如此蝴蜓,但因?yàn)橛?個(gè)值,所以經(jīng)過(guò)了稍微復(fù)雜的計(jì)算俺猿。我們可以自己根據(jù)我們的邏輯來(lái)設(shè)置茎匠。該值即為在update監(jiān)聽(tīng)中的animation.getAnimatedValue()返回值。
需要在ofInt押袍、ofFloat诵冒、ofArgb之外有更復(fù)雜的使用,不僅可以監(jiān)聽(tīng)進(jìn)度變化來(lái)手動(dòng)做設(shè)置谊惭,也可以使用ofObject()傳入自定義的TypeEvaluator以及適當(dāng)?shù)某踔岛徒K值汽馋,來(lái)使代碼更為簡(jiǎn)練。
指定關(guān)鍵幀Keyframe
做動(dòng)畫的時(shí)候不用一幀一幀的話圈盔,而是在有規(guī)律可循的情況下豹芯,指定兩幀,之間的就由軟件完成驱敲,這兩幀就稱之為關(guān)鍵幀铁蹈。
//Keyframe.ofXx(fraction,value),一般使用float众眨,第一個(gè)值是插值器的getInterpolation()的返回值握牧,第二個(gè)參數(shù)為動(dòng)畫在該時(shí)間點(diǎn)的狀態(tài)值
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
//可以添加插值器,插值器作用于該幀和上一幀之間的時(shí)間围辙,所以給第一幀設(shè)置插值器是沒(méi)有用的我碟。
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
kf1.setInterpolator(XXX);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);
rotationAnim.start();
ObjectAnimator的一些補(bǔ)充
可以看到如果想要使用ValueAnimator來(lái)實(shí)現(xiàn)補(bǔ)間動(dòng)畫的視覺(jué)效果,需要監(jiān)聽(tīng)Update姚建,在里面對(duì)我們的控件做相應(yīng)設(shè)置,是比較麻煩的吱殉。所以谷歌在ValueAnimator的基礎(chǔ)上派生出ObjectAnimator掸冤,該類重寫了幾個(gè)方法,舉例說(shuō)明它的原理友雳。
ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY", 0, 3, 1);
在該例中稿湿,之前所說(shuō)的插值器、Evaluator計(jì)算最終獲取一個(gè)值反映在update里押赊,這些都不變饺藤,只是會(huì)增加一步:
- 根據(jù)屬性值拼裝控件的set函數(shù),此處為setScaleY()
- 通過(guò)反射找到控件對(duì)應(yīng)的set函數(shù)并將獲得的值作為set函數(shù)的參數(shù)傳入,此處為setScaleY(float)涕俗;
注意:當(dāng)我們只設(shè)定一個(gè)值罗丰,就相當(dāng)于只設(shè)定了一個(gè)終值,這時(shí)ObjectAnimator會(huì)根據(jù)控件該屬性的getXxx()方法來(lái)獲取到一個(gè)初值再姑。
使用ViewPropertyAnimator進(jìn)行動(dòng)畫處理
先看一個(gè)用ObjectAnimator實(shí)現(xiàn)的多動(dòng)畫實(shí)例
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
再看PropertyValuesHolder來(lái)實(shí)現(xiàn)萌抵,這個(gè)東西起始就是把ofInt、ofFloat那一套的參數(shù)給封裝起來(lái)元镀。在ObjectAnimator內(nèi)部也是使用的PropertyValuesHolder將數(shù)據(jù)封裝后進(jìn)行各種操作绍填。
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
但我們的重點(diǎn)是ViewPropertyAnimator。如果只有一兩個(gè)屬性需要?jiǎng)討B(tài)更改栖疑,ObjectAnimator可以準(zhǔn)確恰當(dāng)?shù)耐瓿扇蝿?wù)讨永。但是如果需要幾個(gè)屬性同時(shí)做動(dòng)畫,或者你想要使用更方便的語(yǔ)法遇革,ViewPropertyAnimator是很合適的住闯。只需要View.animate()獲取到一個(gè)實(shí)例,就可以鏈?zhǔn)秸{(diào)用多種方法了澳淑。
myView.animate().x(50f).y(100f);
它的優(yōu)點(diǎn)在于:
- 相對(duì)于同時(shí)進(jìn)行的動(dòng)畫獨(dú)立發(fā)出自己的重繪要求(invalidate calls)比原,它會(huì)對(duì)其進(jìn)行優(yōu)化,可以減少很多不必要的重繪杠巡。
- 專門針對(duì)View類量窘,簡(jiǎn)潔的鏈?zhǔn)秸{(diào)用,通過(guò)View.animate()獲取到該類實(shí)例后氢拥,你只需要告知View的什么屬性需要變化蚌铜,并設(shè)置to/by即可。加By意味著變化量嫩海,不加By結(jié)尾意味變化到冬殃。
布局動(dòng)畫LayoutAnimation
主要有LayoutAnimation和GridLayoutAnimation。 不做詳細(xì)分析叁怪。
在XML文件中實(shí)現(xiàn)需要在res/anim/xxx.xml中的根節(jié)點(diǎn)為layoutAnimation或者gridLayoutAnimation审葬,并將該文件應(yīng)用到ViewGroup的layoutAnimation標(biāo)簽中
- animation標(biāo)簽指定動(dòng)畫元素
- delay標(biāo)簽設(shè)置動(dòng)畫在上一個(gè)動(dòng)畫結(jié)束后多久執(zhí)行,可用xx%奕谭,可指定具體值涣觉,單位ms。
- animationOrder血柳,normal官册,順序;reverse难捌,倒序膝宁;random鸦难,隨機(jī);
在Java代碼中實(shí)現(xiàn)需要先獲取一個(gè)LayoutAnimationController對(duì)象员淫,也可以做上述設(shè)置合蔽,之后調(diào)用setLayoutAnimation(layoutAnimationController)即可。
需要實(shí)現(xiàn)自定義的效果可以繼承LayoutAnimationController并實(shí)現(xiàn)其getTransformedIndex()方法满粗。
切換動(dòng)畫
Activity
overridePendingTransition
使用overridePendingTransition
(下一個(gè)Activity的進(jìn)入動(dòng)畫辈末,當(dāng)前Activity的消失動(dòng)畫,不需要可傳0)映皆,動(dòng)畫資源放在res/anim挤聘,須在startActivity()/finish()之后調(diào)用。
定義Application的style(AppTheme)
<<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowAnimationStyle">@style/activityAnim</item>
</style>
<!-- 使用style方式定義activity切換動(dòng)畫 -->
<style name="activityAnim">
<item name="android:activityOpenEnterAnimation">@anim/slide_in_top</item>
<item name="android:activityOpenExitAnimation">@anim/slide_in_top</item>
<item name="android:activityCloseEnterAnimation">@anim/slide_in_top</item>
<item name="android:activityCloseExitAnimation">@anim/slide_in_top</item>
</style>
此外還有共享元素和轉(zhuǎn)場(chǎng)動(dòng)畫
Fragment
android.app.Fragment使用屬性動(dòng)畫(res/animator)捅彻,而我們常用的v4包使用的是View Animation(res/anim)组去。除了默認(rèn)的FragmentTransaction.setTransition()來(lái)實(shí)現(xiàn)標(biāo)準(zhǔn)的默認(rèn)動(dòng)畫,還有另外兩種常用方式來(lái)實(shí)現(xiàn)我們自定義的動(dòng)畫步淹。
- 通過(guò)在Fragment類里重寫onCreateAnimator()或v4包里的onCreateAnimation()从隆,此處根據(jù)返回值的不同也證明了上邊所說(shuō)的。要想對(duì)動(dòng)畫的執(zhí)行添加監(jiān)聽(tīng)缭裆,可以在這里實(shí)現(xiàn)键闺。
- 通過(guò)FragmentTransaction.setCustomAnimations(),設(shè)置:enter(進(jìn)入)澈驼,exit(退出)辛燥,popEnter(入棧),popExit(出棧)缝其。注意因?yàn)榘牟煌虯pi版本的不同挎塌,方法咯有差異。
對(duì)于Fragment本身來(lái)說(shuō) 也有一些方法:
- fragment.setEnterTransition()内边,以及Exit榴都、Reenter、Return漠其。以及共享元素setSharedElementEnterTransition()嘴高,setSharedElementExitTransition()。這些方法的參數(shù)必須是android.transition.Transition類型辉懒。
- fragment.setAllowEnterTransitionOverlap()/setAllowReturnTransitionOverlap()阳惹,參數(shù)boolean,設(shè)置是否等之前動(dòng)畫結(jié)束再執(zhí)行下一個(gè)動(dòng)畫眶俩,不然可能會(huì)出現(xiàn)重影。
API使用
最簡(jiǎn)單的
myView.animate().x(50f).y(100f);
屬性值
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
//AnimatorSet有多種使用方法,靈活使用playTogether()快鱼、play()颠印、with()纲岭、before()、after()來(lái)實(shí)現(xiàn)復(fù)雜的效果
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
麻煩點(diǎn)的
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(comtext,R.animator.property_animator);
set.setTarget(myObject);
set.start();
//使用playTogether()线罕、play()止潮、with()、before()钞楼、after()實(shí)現(xiàn)復(fù)雜的效果
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
xml文件方式
視覺(jué)動(dòng)畫建議放xml里喇闸,屬性動(dòng)畫看情況。
- 幀動(dòng)畫 res/drawable/xxx.xml,根節(jié)點(diǎn)<animation-list>
- 補(bǔ)間動(dòng)畫 res/anim/xxx.xml,根節(jié)點(diǎn)<alpha>, <scale>, <translate>, <rotate>, or <set>询件,<set>可嵌套
- 屬性動(dòng)畫 res/animator/xxx.xml燃乍,根節(jié)點(diǎn)必須是<set>, <objectAnimator>, or <animator>,<set>可嵌套
特殊動(dòng)畫
揭露效果動(dòng)畫
顯示需先設(shè)置可見(jiàn)
Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
myView.setVisibility(View.VISIBLE);
anim.start();
隱藏需監(jiān)聽(tīng)動(dòng)畫結(jié)束宛琅,設(shè)置不可見(jiàn)
Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
myView.setVisibility(View.INVISIBLE);
}
});
anim.start();
水波紋動(dòng)畫
基礎(chǔ)
- 有界android:background="?android:attr/selectableItemBackground">
- 無(wú)界android:background="?attr/selectableItemBackgroundBorderless>
對(duì)背景有特殊要求
/drawable-v21/button.xml
用ripple
和指定色?android:colorControlHighlight
包裹刻蟹,colorControlHighlight
默認(rèn)為灰色,可在Theme中重新設(shè)定
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:drawable="@drawable/button_normal" />
</ripple>