Android 動(dòng)畫

Android 3.0之前已有View動(dòng)畫框架Animation(詳見:Android之視圖動(dòng)畫Animation)毕源,但存在一些局限性,當(dāng)某個(gè)元素發(fā)生視圖動(dòng)畫后鞋喇,其響應(yīng)事件位置還在動(dòng)畫前的地方。于是3.0之后,Google提出了屬性動(dòng)畫徙鱼。

Animation的優(yōu)點(diǎn)

1. 版本兼容

不得不說,相對于 Animation,Animator 的版本兼容性還是太差,直到 Android3.0才開始出現(xiàn)的 Animator, 是無法滿足目前開發(fā)環(huán)境2.x 的兼容支持的,而且在 android 官方的 support 包中也沒有對于低版本的 Animator 進(jìn)行支持,所以單從版本兼容來看, Animator 還是不夠的,不過這是系統(tǒng)歷史原因,我們只能接受.

2.實(shí)現(xiàn)效率

同樣的,這也是 Animator 的一個(gè)缺點(diǎn),由于 Animator 是直接通過設(shè)置對象的 setter,getter 方法,來起到動(dòng)畫顯示效果的,所以為了滿足對任意對象調(diào)用正確方法,Animator 使用了 Java 反射機(jī)制, 而 Animation 則是直接通過代碼對矩陣進(jìn)行處理,所以就效率這一方面而言, Animator比不上 Animation

Animator的實(shí)現(xiàn)原理

Animator 動(dòng)畫的實(shí)現(xiàn)機(jī)制說起來其實(shí)更加簡單一點(diǎn),因?yàn)樗鋵?shí)只是計(jì)算動(dòng)畫開啟之后,結(jié)束之前,到某個(gè)時(shí)間點(diǎn)得時(shí)候,某個(gè)屬性應(yīng)該有的值,然后通過回調(diào)接口去設(shè)置具體值,其實(shí) Animator 內(nèi)部并沒有針對某個(gè) view 進(jìn)行刷新,來實(shí)現(xiàn)動(dòng)畫的行為,動(dòng)畫的實(shí)現(xiàn)是在設(shè)置具體值的時(shí)候,方法內(nèi)部自行調(diào)取的類似 invalidate 之類的方法實(shí)現(xiàn)的.也就是說,使用 Animator ,內(nèi)部的屬性發(fā)生了變化.

Animator的優(yōu)點(diǎn)

1. 適用性

在上一個(gè)分析中,我們看到了由于 Animator 使用了反射機(jī)制導(dǎo)致其效率偏低,但是這也帶來了他適用的對象范圍的增加, Animation 僅對 View 這一種對象有用,但是 Animator 可以設(shè)置任意對象的屬性,使其在某段時(shí)間內(nèi)進(jìn)行變化

2. 使用效果

相信大家平時(shí)使用 Animation 的時(shí)候,都有發(fā)現(xiàn)當(dāng)正在進(jìn)行平移移動(dòng),或者動(dòng)畫結(jié)束后,但位置發(fā)生改變的時(shí)候,你點(diǎn)擊之前的位置,點(diǎn)擊效果仍然存在,這就是因?yàn)?View 在內(nèi)部的坐標(biāo)位置其實(shí)沒有發(fā)生改變,而如果使用 Animator 進(jìn)行位移變換,那么你的點(diǎn)擊位置就會(huì)隨著動(dòng)畫效果發(fā)生相應(yīng)改變,所以即使你正處在動(dòng)畫過程中,你也可以去點(diǎn)擊按鈕得到你想要的效果.

-----------------------------------------------

補(bǔ)間動(dòng)畫

  • 視圖動(dòng)畫,也叫Tween(補(bǔ)間)動(dòng)畫可以在一個(gè)視圖容器內(nèi)執(zhí)行一系列簡單變換(位置针姿、大小袱吆、旋轉(zhuǎn)、透明度)距淫。譬如绞绒,如果你有一個(gè)TextView對象,您可以移動(dòng)榕暇、旋轉(zhuǎn)蓬衡、縮放、透明度設(shè)置其文本拐揭,當(dāng)然撤蟆,如果它有一個(gè)背景圖像,背景圖像會(huì)隨著文本變化堂污。
  • 補(bǔ)間動(dòng)畫通過XML或Android代碼定義家肯,建議使用XML文件定義,因?yàn)樗呖勺x性盟猖、可重用性讨衣。
    如下是視圖動(dòng)畫相關(guān)的類繼承關(guān)系:

AlphaAnimation <alpha> 放置在res/anim/目錄下 漸變透明度動(dòng)畫
RotateAnimation <rotate> 放置在res/anim/目錄下 畫面轉(zhuǎn)移旋轉(zhuǎn)動(dòng)果
ScaleAnimation <scale> 放置在res/anim/目錄下 漸變尺寸伸縮動(dòng)畫
TranslateAnimation <translate> 放置在res/anim/目錄下 畫面轉(zhuǎn)換位置移動(dòng)動(dòng)畫效果
AnimationSet <set> 放置在res/anim/目錄下 一個(gè)持有其它動(dòng)畫元素alpha、scale式镐、translate反镇、rotate或者其它set元素的容器
Animation屬性詳解


image.png

android:detachWallpaper setDetachWallpaper(boolean) 是否在壁紙上運(yùn)行
android:duration setDuration(long) 動(dòng)畫持續(xù)時(shí)間,毫秒為單位
android:fillAfter setFillAfter(boolean) 控件動(dòng)畫結(jié)束時(shí)是否保持動(dòng)畫最后的狀態(tài)
android:fillBefore setFillBefore(boolean) 控件動(dòng)畫結(jié)束時(shí)是否還原到開始動(dòng)畫前的狀態(tài)
android:fillEnabled setFillEnabled(boolean) 與android:fillBefore效果相同
android:interpolator setInterpolator(Interpolator) 設(shè)定插值器(指定的動(dòng)畫效果娘汞,譬如回彈等)
android:repeatCount setRepeatCount(int) 重復(fù)次數(shù)
android:repeatMode setRepeatMode(int) 重復(fù)類型有兩個(gè)值歹茶,reverse表示倒序回放,restart表示從頭播放
android:startOffset setStartOffset(long) 調(diào)用start函數(shù)之后等待開始運(yùn)行的時(shí)間你弦,單位為毫秒
android:zAdjustment setZAdjustment(int) 表示被設(shè)置動(dòng)畫的內(nèi)容運(yùn)行時(shí)在Z軸上的位置(top/bottom/normal)惊豺,默認(rèn)為normal

Alpha 屬性
image.png

Scale屬性
image.png

Rotate屬性
image.png

Translate屬性
image.png
LinearLayout layout = (LinearLayout) findViewById(R.id.test_layout );
 ScaleAnimation scaleAnimation = new ScaleAnimation(0,1,0,1);
 scaleAnimation.setDuration(2000);
 LayoutAnimationController layoutAnimationController = new LayoutAnimationController(scaleAnimation,0.5f);
 layoutAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
 layout .setLayoutAnimation(layoutAnimationController);

AnimationSet詳解
AnimationSet繼承自Animation,是上面四種的組合容器管理類禽作,沒有自己特有的屬性尸昧,他的屬性繼承自Animation,所以特別注意旷偿,當(dāng)我們對set標(biāo)簽使用Animation的屬性時(shí)會(huì)對該標(biāo)簽下的所有子控件都產(chǎn)生影響烹俗。

<?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"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

至于補(bǔ)間動(dòng)畫的使用爆侣,Animation還有如下一些比較實(shí)用的方法介紹
image.png

逐幀動(dòng)畫

屬性動(dòng)畫

ObjectAnimator
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "translationX", 300);
objectAnimator1.setInterpolator(new AccelerateInterpolator());
objectAnimator1.setDuration(2000);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);//Animation.INFINITE 表示重復(fù)多次
objectAnimator.setRepeatMode(ValueAnimator.RESTART);//RESTART表示從頭開始,REVERSE表示從末尾倒播
objectAnimator1.start();
Animation 使用setFillAfter(true)讓動(dòng)畫停留在原處

動(dòng)畫屬性值

平移:

translationX和translationY:增量控制view從它布局容器左上角坐標(biāo)偏移
ObjectAnimator.ofFloat(imageView, "translationX", 300f);

rotation 控制view旋轉(zhuǎn):

rotation幢妄、rotationX兔仰、rotationY:控制view繞支點(diǎn)進(jìn)行旋轉(zhuǎn)
ObjectAnimator.ofFloat(imageView, "rotation", 360);

// 翻轉(zhuǎn)
ObjectAnimator rotateX = ObjectAnimator.ofFloat(mTvText, "rotationX", 0, 360);
rotateX.setDuration(2000);
rotateX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        // 屬性動(dòng)畫執(zhí)行時(shí),會(huì)回調(diào)這個(gè)監(jiān)聽器
        // 如果你的屬性沒有觸發(fā)重繪,那你可以在這里加上invalidate()或postInvalidate()
        Log.d(TAG, "onAnimationUpdate: value=" + animation.getAnimatedValue()
                + "fraction=" + animation.getAnimatedFraction());
    }
});

scaleX、scaleY:控制view進(jìn)行縮放:

scaleX磁浇、scaleY:控制view繞支點(diǎn)進(jìn)行縮放
ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0.3f斋陪,1f);

alpha:控制view透明度:

alpha:控制view透明度,默認(rèn)是1(不透明)置吓,0完全透明(不可見)
ObjectAnimator.ofFloat(imageView, "alpha", 1f, 0.3f);

可變數(shù)組參數(shù)

可以有一個(gè)到N個(gè),如果是一個(gè)值的話默認(rèn)這個(gè)值是動(dòng)畫過渡值的結(jié)束值缔赠。如果有N個(gè)值衍锚,動(dòng)畫就在這N個(gè)值之間過渡。
動(dòng)畫監(jiān)聽:

ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 0.5f, 1f);
objectAnimator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {

    }

    @Override
    public void onAnimationEnd(Animator animation) {

    }

    @Override
    public void onAnimationCancel(Animator animation) {

    }

    @Override
    public void onAnimationRepeat(Animator animation) {

    }
});

Android提供了AnimatorListenerAdapter:

 ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 0.5f, 1f);
 objectAnimator1.addListener(new AnimatorListenerAdapter() {
     @Override
     public void onAnimationEnd(Animator animation) {
         super.onAnimationEnd(animation);
     }
 });
XML中使用 ObjectAnimator

放置在res/animator/目錄下
<objectAnimator>屬性解釋:


image.png

XML屬性動(dòng)畫使用方法:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animtor.property_animator);
set.setTarget(myObject);
set.start();

ValueAnimator
ValueAnimator 本身不提供任何動(dòng)畫效果嗤堰,像個(gè)數(shù)值 發(fā)生器戴质,用來產(chǎn)生具有一點(diǎn)規(guī)律數(shù)字。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 500);
valueAnimator.setTarget(mTvText);
valueAnimator.setDuration(2000);
/**
* valueAnimator 必須使用updateListener進(jìn)行接收數(shù)據(jù)
* ValueAnimator不跟屬性進(jìn)行綁定
*/
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
       // 在數(shù)值變化監(jiān)聽器中實(shí)現(xiàn)動(dòng)畫變換
       mTvText.setTranslationX((Float) animation.getAnimatedValue());
   }
});
valueAnimator.start();
PropertyValuesHolder 針對同一個(gè)對象多個(gè)屬性踢匣,同時(shí)作用多種動(dòng)畫
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("translationX", 300f);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("alpha", 1f, 0.5f);
PropertyValuesHolder propertyValuesHolder3 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder propertyValuesHolder4 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(imageView, propertyValuesHolder1, propertyValuesHolder2, propertyValuesHolder3, propertyValuesHolder4)
        .setDuration(5000).start();

AnimatorSet

與PropertyValuesHolder類似告匠,但AnimatorSet多了playTogether(同時(shí)執(zhí)行)、playSequentially(順序執(zhí)行)离唬、play(objectAnimator1).with(objectAnimator2)后专、before、after這些方法協(xié)同工作输莺。
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 1f, 0.5f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "translationY", 300);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(5000);
animatorSet.playTogether(objectAnimator1, objectAnimator2,objectAnimator3);
animatorSet.start();

AnimatorSet set = new AnimatorSet(); // 下面代碼產(chǎn)生的規(guī)則并不能確定anim2與anim3的先后關(guān)系 
 // 下面代碼產(chǎn)生的規(guī)則可間接確定anim2與anim3的先后關(guān)系
set.play(anim1).before(anim2).before(anim3); 
// 下面代碼產(chǎn)生的規(guī)則可完全確定anim1戚哎、anim2、anim3之間的先后關(guān)系
set.play(anim1).before(anim2).after(anim3); 
set.play(anim1).before(anim2); 
set.play(anim2).before(anim3);

xml使用屬性動(dòng)畫

  • res下建立animator文件夾嫂用,然后建立res/animator/main_animator.xml
  • set標(biāo)簽型凳,有一個(gè)orderring屬性設(shè)置為together,還有另一個(gè)值:sequentially(表示一個(gè)接一個(gè)執(zhí)行)嘱函。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:valueType="floatType">
    <objectAnimator
        android:duration="1000"
        android:propertyName="scaleX"
        android:valueFrom="1"
        android:valueTo="0.5" />
    <objectAnimator
        android:duration="1000"
        android:propertyName="scaleY"
        android:valueFrom="1"
        android:valueTo="0.5" />
</set>
<!--  代碼中調(diào)用
    Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(), R.animator.set_animator);
    animator.setTarget(imageView);
    animator.start();
  -->

View的animate方法

Android 3.0后甘畅,谷歌給View增加animate方法直接驅(qū)動(dòng)屬性動(dòng)畫。

 imageView.animate()
 .alpha(0.5f)
 .y(300)
 .setDuration(2000)
 //api min is 16
 .withStartAction(new Runnable() {
     @Override
     public void run() {

     }
 })
 //api min is 16
 .withEndAction(new Runnable() {
     @Override
     public void run() {

     }
 })
 .start();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末往弓,一起剝皮案震驚了整個(gè)濱河市疏唾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌亮航,老刑警劉巖荸实,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缴淋,居然都是意外死亡准给,警方通過查閱死者的電腦和手機(jī)泄朴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來露氮,“玉大人祖灰,你說我怎么就攤上這事∨瞎妫” “怎么了局扶?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叁扫。 經(jīng)常有香客問我三妈,道長,這世上最難降的妖魔是什么莫绣? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任畴蒲,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己峦树,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布蔫骂。 她就那樣靜靜地躺著,像睡著了一般牺汤。 火紅的嫁衣襯著肌膚如雪辽旋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天慧瘤,我揣著相機(jī)與錄音戴已,去河邊找鬼。 笑死锅减,一個(gè)胖子當(dāng)著我的面吹牛糖儡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怔匣,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼握联,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了每瞒?” 一聲冷哼從身側(cè)響起金闽,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎剿骨,沒想到半個(gè)月后代芜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡浓利,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年挤庇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钞速。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嫡秕,死狀恐怖渴语,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情昆咽,我是刑警寧澤驾凶,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站掷酗,受9級(jí)特大地震影響调违,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜汇在,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一翰萨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧糕殉,春花似錦、人聲如沸殖告。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽黄绩。三九已至羡洁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間爽丹,已是汗流浹背筑煮。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粤蝎,地道東北人真仲。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像初澎,于是被迫代替她去往敵國和親秸应。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350