Android中的動(dòng)畫

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)容摘要

  1. 視覺(jué)動(dòng)畫的使用滤钱。(幀動(dòng)畫、補(bǔ)間動(dòng)畫)
  2. 屬性動(dòng)畫的使用及原理脑题。(涉及插值器件缸、估值器、關(guān)鍵幀等)
  3. 布局動(dòng)畫叔遂。(不常用他炊,只簡(jiǎn)單提一下)
  4. 轉(zhuǎn)場(chǎng)動(dòng)畫争剿。(Activity和Fragment)
  5. 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è)置一次屬性

場(chǎng)景1雪标,線性插值效果
場(chǎng)景1零院,線性插值效果
場(chǎng)景2购岗,加減速插值效果
場(chǎng)景2,加減速插值效果
流程示意圖
流程示意圖

結(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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘿辟,一起剝皮案震驚了整個(gè)濱河市舆瘪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌红伦,老刑警劉巖英古,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異昙读,居然都是意外死亡召调,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門箕戳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)某残,“玉大人,你說(shuō)我怎么就攤上這事陵吸〔J” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵壮虫,是天一觀的道長(zhǎng)澳厢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)囚似,這世上最難降的妖魔是什么剩拢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮饶唤,結(jié)果婚禮上徐伐,老公的妹妹穿的比我還像新娘。我一直安慰自己募狂,他們只是感情好办素,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布角雷。 她就那樣靜靜地躺著,像睡著了一般性穿。 火紅的嫁衣襯著肌膚如雪勺三。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天需曾,我揣著相機(jī)與錄音吗坚,去河邊找鬼。 笑死呆万,一個(gè)胖子當(dāng)著我的面吹牛商源,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桑嘶,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼炊汹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了逃顶?” 一聲冷哼從身側(cè)響起讨便,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎以政,沒(méi)想到半個(gè)月后霸褒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盈蛮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年废菱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抖誉。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡殊轴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袒炉,到底是詐尸還是另有隱情旁理,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布我磁,位于F島的核電站孽文,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏夺艰。R本人自食惡果不足惜芋哭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望郁副。 院中可真熱鬧减牺,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)愕贡。三九已至草雕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間固以,已是汗流浹背墩虹。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憨琳,地道東北人诫钓。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像篙螟,于是被迫代替她去往敵國(guó)和親菌湃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容