Android 動畫詳解

??android中酷炫的效果,都離不開動畫的支持喷舀。這里我們詳細介紹一下android中動畫的分類。android的中動畫分為幀動畫淋肾、補間動畫硫麻、屬性動畫。原理各不相同樊卓,實現(xiàn)的效果也大不相同拿愧。下面一一講解三種動畫。

幀動畫

??幀動畫顧名思義就是通過順序一幀一幀播放圖片從而產(chǎn)生動畫效果碌尔,效果類似放電影浇辜。該動畫缺點比較明顯,就是如果圖片過大過多會導致OOM唾戚。幀動畫xml文件放置在drawable目錄下而非anim文件夾下柳洋。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@drawable/ic_launcher_background"
        android:duration="150" />
    <item
        android:drawable="@drawable/ic_launcher_background"
        android:duration="150" />
</animation-list>

補間動畫

??補間動畫是通過對view進行旋轉(zhuǎn)、縮放叹坦、漸變熊镣、透明度變化,而達到的一種動畫效果。是一種漸進式動畫绪囱。并且可以通過組合以上四種操作测蹲,完成復雜的自定義動畫效果。缺點就是只是改變的view的展示狀態(tài)毕箍,但是不會改變view的位置弛房。例如我們將一個button通過位移想左移動100dp,然后停留在終點而柑。但是我們可以發(fā)現(xiàn)展示的位置button點擊無效果文捶,不可以交互。而在button原始位置空白的地方點擊會觸發(fā)button的點擊效果媒咳。也就是button本質(zhì)還是在原來位置粹排,只是展示左移了100dp。

屬性說明

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="4000"
    android:fillAfter="true"
    android:fillBefore="true"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:repeatMode="restart | reverse"
    android:repeatCount = “0”
    android:shareInterpolator="true"
    android:startOffset="float">
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:fromYScale="float"
        android:pivotX="float"
        android:pivotY="float"
        android:toXScale="float"
        android:toYScale="float" />
    <rotate
        android:fromDegrees="float"
        android:pivotX="float"
        android:pivotY="float"
        android:toDegrees="float" />
    <translate
        android:fromXDelta="float"
        android:fromYDelta="float"
        android:toXDelta="float"
        android:toYDelta="float" />
</set>
通用屬性說明:
  • android:duration=""動畫時長涩澡,單位毫秒
  • android:fillAfter="true"動畫完成后是否停留在結(jié)束位置顽耳,默認false
  • android:fillBefore="true"動畫完成后是否停留在起點位置。默認true妙同,優(yōu)先級低于fillAfter
  • android:interpolator為動畫的變化速度【可以單獨設置射富,可以直接放在set里面】
      可以設置多種速度變化方式,這里只列出勻速粥帚、加速胰耗、減速
      勻速 @android:anim/linear_interpolator
      加速 @android:anim/accelerate_interppolator
      減速 @android:anim/decelerate_interpolator
  • android:repeatMode="restart | reverse"動畫重復策略 restart從起點位置(正序)重復,reverse從結(jié)束位置(倒序)重復
  • android:repeatCount = “0”重復次數(shù) “infinite”為無線重復
  • android:shareInterpolator="true"動畫集合中的動畫是否公用一個差值器
  • android:startOffset="float"動畫延遲時間
透明度動畫

透明度動畫芒涡,通過改變view的透明度展示動畫柴灯。對應AlphaAnimation和<alpha>xml標簽

  • android:fromAlpha="float" 起始透明度,取值范圍(-1.0~1.0)
  • android:toAlpha="float"結(jié)束時透明度费尽,取值范圍(-1.0~1.0)
縮放動畫

縮放動畫赠群,通過修改view的大小展示動畫。對應ScaleAnimation類和<scale>xml表情

  • android:fromXScale="float"動畫在水平方向X的起始縮放倍數(shù)
  • android:fromYScale="float"動畫在水平方向Y的結(jié)束縮放倍數(shù)
  • android:toXScale="float"動畫在豎直方向X的結(jié)束縮放倍數(shù)
  • android:toYScale="float"動畫在豎直方向Y的結(jié)束縮放倍數(shù)

    // 0.0表示收縮到?jīng)]有旱幼;1.0表示正常無伸縮
    // 值小于1.0表示收縮查描;值大于1.0表示放大

  • android:pivotX="float"縮放中心點的x坐標
  • android:pivotY="float"縮放中心點的y坐標

// pivotX pivotY,可取值為數(shù)字,百分比柏卤,或者百分比p
// 設置為數(shù)字時(如50)叹誉,軸點為View的左上角的原點在x方向和y方向加上50px的點。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.ABSOLUTE闷旧。
// 設置為百分比時(如50%),軸點為View的左上角的原點在x方向加上自身寬度50%和y方向自身高度50%的點钧唐。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.RELATIVE_TO_SELF忙灼。
// 設置為百分比p時(如50%p),軸點為View的左上角的原點在x方向加上父控件寬度50%和y方向父控件高度50%的點。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.RELATIVE_TO_PARENT

旋轉(zhuǎn)動畫

通過旋轉(zhuǎn)view展示動畫该园。對應RotateAnimation類和<rotate>xml標簽

  • android:fromDegrees="float"動畫開始時 視圖的旋轉(zhuǎn)角度(正數(shù) = 順時針酸舍,負數(shù) = 逆時針)
  • android:toDegrees="float"動畫結(jié)束時 視圖的旋轉(zhuǎn)角度(正數(shù) = 順時針,負數(shù) = 逆時針)
  • android:pivotX="float"旋轉(zhuǎn)中心點的x坐標 具體如上縮放中心點參數(shù)解釋
  • android:pivotY="float"旋轉(zhuǎn)中心點的y坐標 具體如上縮放中心點參數(shù)解釋
平移動畫

平移動畫里初,更改view的展示位置展示動畫啃勉。對應TranslateAnimation類和<translate>xml表情

  • android:fromXDelta="float"view在水平x方向的起始值
  • android:fromYDelta="float"view在水平y(tǒng)方向的起始值
  • android:toXDelta="float"view在水平x方向的結(jié)束值
  • android:toYDelta="float" view在水平y(tǒng)方向的結(jié)束值
具體動畫的使用

應用動畫xml配置

TextView textDemo = findViewById(R.id.text_demo);
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.rotate_animation_test);
textDemo.startAnimation(animation);

使用java類配置動畫,具體參數(shù)類同xml參數(shù)双妨,建議使用xml配置動畫

AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 2.0f);
textDemo.startAnimation(alphaAnimation);
監(jiān)聽動畫
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        //動畫開始回調(diào)
    }
    @Override
    public void onAnimationEnd(Animation animation) {
        //動畫結(jié)束回調(diào)
    }
    @Override
    public void onAnimationRepeat(Animation animation) {
        //動畫重復時回調(diào)
    }
});
View動畫特殊使用場景
  • Activity 的切換效果
    1. 使用public void overridePendingTransition(int enterAnim, int exitAnim)給activity切換添加動畫效果淮阐。調(diào)用時機在startActivity()或者finish()方法之后調(diào)用,否則不起作用刁品。
    2. 配置theme的style
    <style name="AnimationActivity" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/push_left_in</item>
        <item name="android:activityCloseExitAnimation">@anim/push_left_in</item>
        <item name="android:activityOpenExitAnimation">@anim/push_left_out</item>
        <item name="android:activityCloseEnterAnimation">@anim/push_left_out</item>
    </style>
    
  • Fragement 的切換效果
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
    fragmentTransaction.setCustomAnimations()
    
  • 視圖組(ViewGroup)中子元素的出場效果
    簡單來說就是可以在 ViewGroup 的添加一個入場動畫泣特,這個 ViewGroup 的所有子元素都會按照你設計的順序執(zhí)行一遍動畫,至于子元素的范圍目測是直接子元素才行挑随。常見的有
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/rotate_animation_test" 
    android:delay="20"
    android:interpolator=""
    android:animationOrder="random"/>
  • android:animation="@anim/rotate_animation_test"
  • android:delay="20"是子元素開始動畫的時間延遲状您,比如子元素入場動畫的時間周期為300ms,那么0.5就代表每個子元素都需要延遲150ms才能播放入場動畫兜挨「嗝希總體來說柒桑,第一個子元素延遲150ms開始播放入場動畫,第二個子元素延遲300ms開始播放入場動畫,依次類推仇奶。
  • android:animationOrder="random" 子元素入場順序reverse倒序 normal正常 random隨機
    應用:
<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="3dp"
    android:layoutAnimation="@anim/rotate_animation_test"
    android:layout_centerInParent="true">
   ......子view
</RelativeLayout>

屬性動畫

??屬性動畫本質(zhì)是通過改變對象的屬性(例如:x,y等屬性),來實現(xiàn)動畫的,所以基本上是無所不能的氯庆,只要對象有這個屬性仁讨,就能實現(xiàn)動畫效果。屬性動畫是在api11的新特性,通過動態(tài)的改變view的屬性從而達到動畫效果礁哄。雖然可以使用nineoldandroid庫向下兼容之拨,但是兼容本質(zhì)是使用補間動畫完成烁竭,也就是說不會更改view的屬性睬魂,也不會更改view的位置氯哮。屬性動畫比較常用的類: ValueAnimator姆打、ObjectAnimator肠虽、AnimationSet评抚,其中ObjectAnimator是ValueAnimator的子類啸如,而AnminationSet是動畫集合

單個動畫
ObjectAnimator animator = ObjectAnimator
        .ofInt(textDemo, "backgroundColor", 0XffFF0000, 0Xff0000FF)
        .setDuration(2000);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(10);
animator.start();
動畫集合
AnimatorSet animatorSet = new AnimatorSet();
ValueAnimator translationX = ObjectAnimator.ofFloat(textDemo, "translationX", 200f);
ValueAnimator animator = ObjectAnimator
        .ofInt(textDemo, "backgroundColor", 0XffFF0000, 0Xff0000FF);
animatorSet.playTogether(translationX,animator);
animatorSet.setDuration(1000).start();

動畫配置同樣可以使用xml配置帘不,參數(shù)類似,這里不做詳細說明寞焙。

差值器和估值器

差值器(Interpolator)

根據(jù)時間流逝百分比計算當前屬性改變百分比储狭。同xml配置動畫中的 android:interpolator屬性配置,常見有LinearInterpolator(線性差值器)捣郊、AccelerateDecelerateInterpolator(加速減速差值器)
等辽狈。自定義需要實現(xiàn)Interpolator或者TimeInterpolator。Interpolator接口繼承TimeInterpolator呛牲。

// Interpolator接口
public interface Interpolator extends TimeInterpolator{ 
    // 內(nèi)部只有一個方法
     float getInterpolation(float input) {  
         // 參數(shù)說明
         // input值值變化范圍是0-1刮萌,且隨著動畫進度(0% - 100% )均勻變化
        // 即動畫開始時,input值 = 0娘扩;動畫結(jié)束時input = 1
        // 而中間的值則是隨著動畫的進度(0% - 100%)在0到1之間均勻增加
      ...// 插值器的計算邏輯
      return xxx着茸;
      // 返回的值就是用于估值器繼續(xù)計算的fraction值,下面會詳細說明
    }  
// TimeInterpolator接口
// 同上
public interface TimeInterpolator {  
    float getInterpolation(float input);  
}
估值器(TypeEvaluator)

根據(jù)當前屬性改變百分比計算改變后的屬性值琐旁。屬性動畫特有的屬性涮阔。自定義估值器需要實現(xiàn)TypeEvaluator接口。

public interface TypeEvaluator {  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
// 參數(shù)說明
// fraction:插值器getInterpolation()的返回值
// startValue:動畫的初始值
// endValue:動畫的結(jié)束值
        ....// 估值器的計算邏輯
        return xxx旋膳;
        // 賦給動畫屬性的具體數(shù)值
        // 使用反射機制改變屬性變化
// 特別注意
// 那么插值器的input值 和 估值器fraction有什么關系呢澎语?
// 答:input的值決定了fraction的值:input值經(jīng)過計算后傳入到插值器的getInterpolation(),然后通過實現(xiàn)getInterpolation()中的邏輯算法验懊,根據(jù)input值來計算出一個返回值擅羞,而這個返回值就是fraction了
    }  
}

可以對任意屬性做屬性動畫,屬性動畫要求動畫作用的對象提供該屬性的get()和set()方法义图。因為屬性動畫本質(zhì)就是根據(jù)外界傳遞的對象屬性的初始值和終點值减俏,然后根據(jù)估值器和差值器計算屬性值,不斷調(diào)用屬性的set方法碱工,通過時間的推移所傳遞的值娃承,越來越近終點值奏夫。
注意:

  • 對象屬性必須提供對應的set方法,而且如果沒有初始值傳入的情況下必須要設置get方法历筝,因為 系統(tǒng)要獲取初始值酗昼,如果沒有滿足條件則程序cash
  • 對象屬性的set方法對屬性做出改變,需要能夠通過某種方法表示出來梳猪。帶來ui展示效果的改變麻削。否則動畫不會生效。

ValueAnimator

使用ValueAnimator通過監(jiān)聽動畫過程春弥,自己改變對象屬性完成動畫

        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
        valueAnimator.setDuration(2000);//動畫持續(xù)時間
        valueAnimator.setRepeatCount(0);//重復次數(shù)
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);//重復方式呛哟,
        valueAnimator.setStartDelay(20);//開始前延遲時間
        valueAnimator.setEvaluator(new IntEvaluator());//估值器
        valueAnimator.setInterpolator(new LinearInterpolator());//差值器
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //獲取當前動畫屬性值,即1~100
                Integer animatedValue = (Integer) animation.getAnimatedValue();
                //獲取動畫的百分比
                float animatedFraction = animation.getAnimatedFraction();
                ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();
                int width = layoutParams.width;
                int height = layoutParams.height;
                layoutParams.height = height + 1;
                layoutParams.width=width+1;
                Log.e(TAG,"animatedValue: "+animatedValue+" animatedFraction : "+animatedFraction
                +" width : "+layoutParams.width+" height : "+layoutParams.height);
                textView.requestLayout();
            }
        });
        valueAnimator.start();
    }

注意事項

  • OOM注意匿沛,在幀動畫中如果圖片過大扫责、數(shù)量過多容易出現(xiàn)
  • 內(nèi)存泄漏, 切記在activity銷毀時逃呼,停止動畫鳖孤。否則一些無限循環(huán)動畫將導致activity不能釋放而內(nèi)存泄漏。出現(xiàn)在屬性動畫中蜘渣,view動畫不存在此類問題
  • 兼容性問題淌铐,屬性動畫出現(xiàn)在android3.0以后,雖然有兼容包蔫缸,但是內(nèi)部實行是view動畫腿准,注意視覺位置和真實位置差異
  • View動畫即補間動畫,是改變view的視覺位置拾碌,改變view的影像展示位置吐葱,而不改變真實位置。注意交互體驗校翔〉芘埽可能會出現(xiàn)view動畫結(jié)束后,view無法隱藏的問題及setVisibility(View.GONE)失效防症。此時調(diào)用view.clearAnimation()清除動畫孟辑。可修復此類問題
  • 注意適配蔫敲,動畫中的屬性都是px的但是切換展示過程中使用dp饲嗽,
  • 交互問題,在android3.0以前屬性動畫和view動畫都是改變影像位置奈嘿,不改變真實位置貌虾,例如點擊依舊在原位置點擊響應,而不是新位置裙犹,在3.0以后屬性動畫view真實位置隨著影像位置而變交互即在移動后的位置尽狠,而view動畫仍然在原始位置衔憨。
  • 使用動畫的過程中,建議使用硬件加速袄膏,提高動畫的流暢性践图。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哩陕,隨后出現(xiàn)的幾起案子平项,更是在濱河造成了極大的恐慌,老刑警劉巖悍及,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異接癌,居然都是意外死亡心赶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門缺猛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缨叫,“玉大人,你說我怎么就攤上這事荔燎〕芾眩” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵有咨,是天一觀的道長琐簇。 經(jīng)常有香客問我,道長座享,這世上最難降的妖魔是什么婉商? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮渣叛,結(jié)果婚禮上丈秩,老公的妹妹穿的比我還像新娘。我一直安慰自己淳衙,他們只是感情好蘑秽,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著箫攀,像睡著了一般肠牲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匠童,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天埂材,我揣著相機與錄音,去河邊找鬼汤求。 笑死俏险,一個胖子當著我的面吹牛严拒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播竖独,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼裤唠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了莹痢?” 一聲冷哼從身側(cè)響起种蘸,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竞膳,沒想到半個月后航瞭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡坦辟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年刊侯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锉走。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡滨彻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挪蹭,到底是詐尸還是另有隱情亭饵,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布梁厉,位于F島的核電站辜羊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏懂算。R本人自食惡果不足惜只冻,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望计技。 院中可真熱鬧喜德,春花似錦、人聲如沸垮媒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睡雇。三九已至萌衬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間它抱,已是汗流浹背秕豫。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人混移。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓祠墅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親歌径。 傳聞我的和親對象是個殘疾皇子毁嗦,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353