Android提供了三種類型動畫:一開始的傳統(tǒng)動畫(包含兩種類型:逐幀動畫和補(bǔ)間動畫(View動畫))和Android3.0 之后出現(xiàn)的
屬性動畫。
逐幀動畫:基于單元格的動畫,每一幀顯示一個不同的drawable。一幀一幀的順序播放。
補(bǔ)間動畫:補(bǔ)間動畫應(yīng)用于view,通過對其位置,大小,旋轉(zhuǎn)和透明度的改變,讓view動起來。
屬性動畫:屬性動畫幾乎可以讓應(yīng)用程序中任何對象動起來。所有補(bǔ)間動畫的內(nèi)容,都可以通過屬性動畫實(shí)現(xiàn)。
下面逐一介紹:
注:這篇文章偏重于以xml方式實(shí)現(xiàn)相應(yīng)動畫效果。
逐幀動畫
逐幀動畫(Frame-by-frame Animations)從字面上理解就是一幀一幀的播放圖片,類似卡通動畫。
目標(biāo):
實(shí)現(xiàn)如下圖效果:
步驟:
1.在res/drawable目錄下新建loading_frame.xml文件:
根節(jié)點(diǎn)是animation-list,內(nèi)部由一到多個<item>節(jié)點(diǎn)組成,
oneshot屬性表示是否只播放一次(true:一次;false:循環(huán)播放).
item節(jié)點(diǎn)聲明是一個動畫幀,其中 android:drawable屬性定義要顯示的圖像,android:druation代表此幀持續(xù)的時間,毫秒為單位。
注:在AndroidStudio中強(qiáng)制規(guī)定帶animation-list節(jié)點(diǎn)xml文件必須放在res/drawable文件下(eclipse(ADT)貌似支持任意放res/drawable和res/anim)。在androidStudio中若放在res/anim下會報(bào)錯:
2.新建頁面布局activity_frame.xml:如上圖布局很簡單 上面一個imageview,下面兩個button,都水平居中(相對于parent)。
? ?設(shè)置imageView背景為loading_frame: android:background="@drawable/loading_frame" ?這里就不貼代碼了。
3.新建FrameActivity
當(dāng)然為了避免animationDrawable帶來的內(nèi)存泄露,建議在onDestroy方法中做如下操作:
注意:
幀數(shù)比較多的動畫不建議用逐幀動畫實(shí)現(xiàn),其一會顯得卡頓,其二容易引起OOM。
補(bǔ)間動畫
補(bǔ)間動畫(Tween Animation):支持通過對View的內(nèi)容進(jìn)行一系列的圖形變換來實(shí)現(xiàn)動畫效果。使用補(bǔ)間動畫進(jìn)行改變透明度、縮放、旋轉(zhuǎn)、平移等操作比通過手動重繪Canvas達(dá)到相似效果要消耗更少的資源,在實(shí)現(xiàn)上也更加簡便。
補(bǔ)間動畫使用XML語言來定義時,其XML文件被放在項(xiàng)目的res/anim/目錄下。
由于相關(guān)的屬性有點(diǎn)多,在這先把它們公用的屬性做一下說明,然后再對每個分類下的特定屬性在做對應(yīng)動畫效果時,進(jìn)行描述。
在上面圖表中可以看到第二行有一個interpolator屬性,表示動畫所采用的插值器。插值器影響動畫的播放速度。可以不指定,默認(rèn)為加速減速插值器(@android:anim/accelerate_decelerate_interpolator")。
當(dāng)然安卓也支持自定義插值器,具體網(wǎng)上有許多相關(guān)博客教程,可自行搜索,這里先不作介紹。
說了這么多,都好像背書的趕腳了。下面我們來玩玩吧
漸變
1.在res/anim/目錄下新建view_alpha.xml
(從頭播放重復(fù)一次)
這里有兩個屬性是alpha獨(dú)有的:
android:fromAlpha-動畫開始時操作對象的alpha值
android:toAlpha-動畫終止時操作對象的alpha值
2.在對應(yīng)view上應(yīng)用動畫:
3.看一下運(yùn)行結(jié)果:
由于默認(rèn)android:fillBefore為true,所以動畫運(yùn)行結(jié)束時會回到初始狀態(tài)
縮放
1.在res/anim/目錄下新建view_scale.xml
(反向播放重復(fù)兩次,保持最后狀態(tài))
屬性:
android:fromXScale-動畫起始時,X軸坐標(biāo)的伸縮尺寸。(0.0表示收縮到?jīng)]有。1.0表示正常沒伸縮。>1.0表示放大。<1.0表示收縮。)
android:toXScale-動畫結(jié)束時X軸坐標(biāo)的伸縮尺寸
android:fromYScale-動畫起始時Y軸坐標(biāo)的伸縮尺寸
android:toYScale-動畫結(jié)束時Y軸坐標(biāo)的伸縮尺寸
android:pivotX-縮放動畫作用點(diǎn)在X軸方向上的位置。(android:pivotX=”50”表示絕對定位,相對于零點(diǎn)偏移50 ? –>Animation.ABSOLUTE ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?android:pivotX=”50%”表示相對控件本身 ? ?–>Animation.RELATE_TO_SELF
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?android:pivotX=”50%p”表示相對控件的父控件 ?–>Animation.RELATE_TO_PARENT)
android:pivotY-縮放動畫作用點(diǎn)在Y軸方向上的位置(同上pivotX)
2.應(yīng)用動畫:
3.運(yùn)行結(jié)果:
旋轉(zhuǎn)
1.在res/anim/目錄下新建view_rotate.xml
(運(yùn)行過程:先向相反的方向改變一點(diǎn),然后在加速播放至超出結(jié)束值一點(diǎn),然后在緩慢回到結(jié)束值)
屬性:
android:fromDegrees-動畫起始的角度(可正可負(fù))
android:toDegrees-動畫終止的角度(可正可負(fù))
android:pivotX-旋轉(zhuǎn)作用點(diǎn)在X軸方向上的位置
android:pivotY-旋轉(zhuǎn)作用點(diǎn)在Y軸方向上的位置
2.應(yīng)用動畫
3.運(yùn)行結(jié)果
平移
1.在res/anim/目錄下新建view_translate.xml:
(運(yùn)行過程:先向相反的方向改變一點(diǎn),然后在加速播放至超出結(jié)束值一點(diǎn),然后在緩慢回到結(jié)束值)
屬性:
android:fromXDelta-平移動畫起始位置X軸坐標(biāo) (android:fromXDelta=”50”表示絕對定位,相對于零點(diǎn)偏移50 ? –>Animation.ABSOLUTE
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? android:fromXDelta=”50%”表示相對控件本身 –>Animation.RELATE_TO_SELF
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?android:fromXDelta=”50%p”表示相對控件的父控件–>Animation.RELATE_TO_PARENT)
android:toXDelta-平移動畫結(jié)束位置X軸坐標(biāo)
android:fromYDelta-平移動畫起始位置Y軸坐標(biāo)
android:toYDelta-平移動畫結(jié)束位置Y軸坐標(biāo)
2.應(yīng)用
3.運(yùn)行結(jié)果
組合
1.在res/anim/目錄下新建view_set.xml:
屬性:
android:shareInterpolator-是否對子動畫設(shè)置相同的插值器
先來推測一下運(yùn)行過程:前1.5秒執(zhí)行漸變,然后圖片以自身中心為旋轉(zhuǎn)軸心,從60度轉(zhuǎn)到325度,耗時1.8s。
2.應(yīng)用
3.運(yùn)行效果:
額。。。跟當(dāng)初推測的不一致。它一開始就轉(zhuǎn)了60度然后再漸變,再轉(zhuǎn)到325度。也就是說吧<rotate>的初始狀態(tài)給先執(zhí)行了,因?yàn)槟J(rèn)的fillBefore屬性為true。好吧,在<rotate>中設(shè)置fillBefore為false,再試一次:
再看看運(yùn)行效果---
是不是fillBefore失效了???看看源碼,進(jìn)去Animation類中,有一個mFillEabled變量(主要看上面注釋):
想到有個屬性android:fillEnabled 與fillBefore是否被忽略有關(guān),fillEnabled默認(rèn)值是false(這時fillBefore設(shè)置為false失效)。
那將android:fillEnabled設(shè)為true試試:
看看效果:
OK ?要的就是這種效果(是不是很有朦朧美,哈哈)。
LayoutAnimation(View動畫特殊使用場景)
? LayoutAnimation作用于ViewGroup,可控制其子元素的出場效果。經(jīng)常看到有些listview,它每個item都以動畫的形式出現(xiàn)。這里我們也來實(shí)現(xiàn)一個類似的功能吧!
1.為子元素指定入場動畫(在res/anim下新建anim_layout_item.xml)
2.定義layoutAnimtion-res/anim下新建anim_layout.xml
屬性:
android:delay - 先從字面意思理解就是延遲,具體什么意思 通過下面實(shí)現(xiàn) 再看
android:animationOrder - 動畫順序 有三種選項(xiàng) :normal,reverse,random ?具體各自有什么效果 通過下面實(shí)現(xiàn) 再看
android:animation 指定子元素具體動畫
3.為listview指定android:layoutAnimation屬性:
看看運(yùn)行結(jié)果:
貌似沒什么效果。那將anim_layout.xml中修改一下---android:delay="1",
從上面兩圖可以看到,當(dāng)delay=0時,各item同時出現(xiàn)在頁面中,當(dāng)delay=1時,各item是依次以設(shè)定的動畫方式出現(xiàn),細(xì)心一點(diǎn)看,幾乎當(dāng)上一個item到達(dá)最左部時(完成入場動畫),下一個item開始進(jìn)入視圖播放入場動畫。所以delay應(yīng)該指的是子元素的入場延遲。具體來說,第一個子元素延遲500ms*1(anim_layout_item.xml中設(shè)置duration=500,即子元素入場動畫周期為500ms)才開始播放入場動畫,第2個子元素延遲500ms*1*2播放入場動畫,以此類推。我們再來驗(yàn)證一下,將delay設(shè)置為0.5,推測應(yīng)該出現(xiàn)的效果為:上一個item大概到達(dá)中間位置時,下一個item開始入場:
delay的作用大概搞清楚了,下面來看看animationOrder的三個選項(xiàng):normal 上面幾個圖都是設(shè)為這個選項(xiàng)的,下面就只用看其他兩種選項(xiàng)下的運(yùn)行效果。
從上面幾個動圖的效果對比可以看到
android:animationOrder屬性是用來表示子元素動畫的順序的。默認(rèn)即為normal:順序顯示,排在前面item先開始入場;reverse:倒序;random:隨機(jī)。
當(dāng)然view動畫還可用于實(shí)現(xiàn)activity的切換效果等場景(5.0后,geogle推出的新的轉(zhuǎn)場動畫,還支持共享元素)。這里就不一一介紹了。
還有屬性動畫沒有介紹,屬性動畫非常強(qiáng)大,可以通過它實(shí)現(xiàn)絢麗的效果。鑒于它的相關(guān)內(nèi)容比較多,一時半會也說不完,下次有空再整理學(xué)習(xí)吧。
感謝:
https://developer.android.google.cn/guide/topics/graphics/view-animation.html
https://developer.android.google.cn/guide/topics/graphics/drawable-animation.html