概述
在Android開發(fā)的過程中紊浩,View的變化是很常見的窖铡,如果View變化的過程沒有動畫來過渡而是瞬間完成,會讓用戶感覺很不友好坊谁,因此學習好Android系統(tǒng)中的動畫框架是很重要的础废。
Android系統(tǒng)提供了兩個動畫框架:屬性動畫框架和View動畫框架谈截。 兩個動畫框架都是可行的選項,但是屬性動畫框架通常是首選的使用方法,因為它更靈活媒殉,并提供更多的功能。 除了這兩個框架摘盆,還可以使用Drawable動畫(即逐幀動畫坛梁,AnimationDrawable),它允許你加載Drawable資源并逐幀地顯示它們膘融。
1> View動畫框架
View動畫框架是舊的框架芙粱,只能用于Views。 比較容易設置和能滿足許多應用程序的需要氧映。View動畫框架中一共提供了AlphaAnimation(透明度動畫)春畔、RotateAnimation(旋轉動畫)、ScaleAnimation(縮放動畫)岛都、TranslateAnimation(平移動畫)四種類型的補間動畫律姨;并且View動畫框架還提供了動畫集合類(AnimationSet),通過動畫集合類(AnimationSet)可以將多個補間動畫以組合的形式顯示出來臼疫。View動畫框架中動畫相關類的繼承關系如下圖所示:
2> 屬性動畫框架
與屬性動畫相比View動畫存在一個缺陷择份,View動畫改變的只是View的顯示,而沒有改變View的響應區(qū)域烫堤,并且View動畫只能對View做四種類型的補間動畫荣赶。因此Google在Android3.0(API級別11)及其后續(xù)版本中添加了屬性動畫框架凤价,從名稱中就可以知道只要某個類具有屬性(即該類含有某個字段的set和get方法),那么屬性動畫框架就可以對該類的對象進行動畫操作(其實就是通過反射技術來獲取和執(zhí)行屬性的get拔创,set方法)利诺,同樣屬性動畫框架還提供了動畫集合類(AnimatorSet),通過動畫集合類(AnimatorSet)可以將多個屬性動畫以組合的形式顯示出來剩燥。屬性動畫框架中動畫相關類的繼承關系如下圖所示:
3> Drawable 動畫
可繪制動畫通過一個接一個地加載一系列Drawable資源來創(chuàng)建動畫慢逾。 這是一個傳統(tǒng)的動畫,它是用一系列不同的圖像創(chuàng)建的灭红,按順序播放侣滩,就像一卷電影;逐幀動畫中動畫相關類的繼承關系如下圖所示:
預備知識
1. 時間插值器
對于補間動畫:時間插值器(TimeInterpolator)的作用是根據時間流逝的百分比計算出動畫進度的百分比比伏。有了動畫進度的百分比胜卤,就可以很容易的計算出動畫開始的關鍵幀與將要顯示的幀之間的差異(通過Transformation類的對象表示),下面展示TranslateAnimation類中如何根據動畫進度的百分比計算出動畫開始的關鍵幀與將要顯示的幀之間的差異:
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float dx = mFromXDelta;
float dy = mFromYDelta;
if (mFromXDelta != mToXDelta) {
dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
}
if (mFromYDelta != mToYDelta) {
dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
}
t.getMatrix().setTranslate(dx, dy);
}
上面源碼中applyTransformation方法的第一個參數就是通過時間插值器(TimeInterpolator)獲取的動畫進度的百分比赁项。
然后根據幀之間的差異繪制出將要顯示的幀葛躏,以此類推從而形成動畫的效果。
對于屬性動畫:時間插值器(TimeInterpolator)的作用是根據時間流逝的百分比計算出動畫進度的百分比(即屬性值改變的百分比)悠菜。
Android提供了常用的時間插值器如下表所示:
Interpolator class | Resource ID |
---|---|
AccelerateDecelerateInterpolator | @android:anim/accelerate_decelerate_interpolator |
AccelerateInterpolator | @android:anim/accelerate_interpolator |
AnticipateInterpolator | @android:anim/anticipate_interpolator |
AnticipateOvershootInterpolator | @android:anim/anticipate_overshoot_interpolator |
BounceInterpolator | @android:anim/bounce_interpolator |
CycleInterpolator | @android:anim/cycle_interpolator |
DecelerateInterpolator | @android:anim/decelerate_interpolator |
LinearInterpolator | @android:anim/linear_interpolator |
OvershootInterpolator | @android:anim/overshoot_interpolator |
上面列舉的常用的時間插值器對應的類與時間插值器(TimeInterpolator)之間的繼承關系如下圖所示:
為了比較直觀的感受到Android提供的常用時間插值器的效果舰攒,我通過程序繪制出了動畫進度的百分比隨著時間流逝的百分比變化的波形圖(波形圖的橫向代表時間流逝的百分比,縱向代表動畫進度的百分比悔醋,時間流逝的百分比我一共選取了11個值摩窃,分別為0、0.1芬骄、以此類推一直到1)猾愿,如下所示:
2. 類型估值器
類型估值器(TypeEvaluator)是針對于屬性動畫框架的,對于View動畫框架是不需要類型估值器(TypeEvaluator)的账阻。
類型估值器(TypeEvaluator)的作用是根據屬性值改變的百分比計算出改變后的屬性值蒂秘。由于屬性動畫實際上作用的是對象的屬性,而屬性的類型是不同的淘太,因此Android內置了一些常用的類型估值器來操作不同類型的屬性姻僧,如下圖所示:
View動畫框架
使用View動畫框架可以在Views上執(zhí)行補間動畫。 補間動畫是指只要指定動畫的開始蒲牧、動畫結束的"關鍵幀"撇贺,而動畫變化的"中間幀"由系統(tǒng)計算并補齊;無論動畫怎樣改變View的顯示區(qū)域(移動或者改變大斜馈)松嘶,持有該動畫的View的邊界不會自動調整來適應View的顯示區(qū)域, 即使如此挎扰,該動畫仍將被繪制在超出其視圖邊界并且不會被剪裁翠订, 但是缓升,如果動畫超過父視圖的邊界,則會出現裁剪蕴轨。在Android中的View動畫框架中一共提供了AlphaAnimation(透明度動畫)、RotateAnimation(旋轉動畫)骇吭、ScaleAnimation(縮放動畫)橙弱、TranslateAnimation(平移動畫)四種類型的補間動畫。
FILE LOCATION:
res/anim/filename.xml
The filename will be used as the resource ID.
COMPILED RESOURCE DATATYPE:
Resource pointer to an Animation.
RESOURCE REFERENCE:
In Java: R.anim.filename
In XML: @[package:]anim/filename
語法:
<?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>
<set>標簽表示補間動畫的集合燥狰,對應于AnimationSet類棘脐,所以上面語法中的<set>標簽可以包含多個補間動畫的標簽;并且補間動畫的集合中還可以包含補間動畫的集合龙致。
<set>標簽的相關屬性如下所示:
android:interpolator
Interpolator resource. 設置動畫集合所采用的插值器蛀缝,默認值為@android:anim/accelerate_decelerate_interpolator
android:shareInterpolator
Boolean. 表示集合中的動畫是否共享集合的插值器。當值為true且集合沒有設置插值器目代,
此時集合中的動畫就會使用默認的插值器@android:anim/accelerate_decelerate_interpolator屈梁,
但是你也可以為集合中的動畫單獨指定所需的插值器。
AlphaAnimation(透明度動畫)
上面語法中的<alpha>標簽代表的就是透明度動畫榛了,顧名思義透明度動畫就是通過不斷改變View的透明度實現動畫的效果在讶。
<alpha>標簽相關屬性如下所示:
android:fromAlpha
Float. 設置透明度的初始值,其中0.0是透明霜大,1.0是不透明的构哺。
android:toAlpha
Float. 設置透明度的結束值,其中0.0是透明战坤,1.0是不透明的曙强。
舉例如下:
首先展示一下動畫效果:
實現代碼如下:
首先通過xml定義一個透明度動畫(AlphaAnimation),代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<alpha
android:duration="2000"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>
接著將上面定義的透明度動畫(AlphaAnimation)設置為ImageView的src途茫,然后通過startAnimation播放動畫碟嘴,代碼如下:
<ImageView
android:id="@+id/image"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:src="@drawable/second_pic"
android:scaleType="centerCrop"
android:alpha="1.0" >
</ImageView>
loadAnimation = AnimationUtils.loadAnimation(getActivity(),
R.anim.base_animation_alpha);
loadAnimation.setFillAfter(true);
image.startAnimation(loadAnimation);
ScaleAnimation(縮放動畫)
上面語法中的<scale>標簽代表的就是縮放動畫,顧名思義縮放動畫就是通過不斷縮放View的寬高實現動畫的效果慈省。
<scale>標簽相關屬性如下所示:
android:fromXScale
Float. 水平方向縮放比例的初始值臀防,其中1.0是沒有任何變化。
android:toXScale
Float. 水平方向縮放比例的結束值边败,其中1.0是沒有任何變化袱衷。
android:fromYScale
Float. 豎直方向縮放比例的初始值,其中1.0是沒有任何變化笑窜。
android:toYScale
Float. 豎直方向縮放比例的結束值致燥,其中1.0是沒有任何變化。
android:pivotX
Float. 縮放中心點的x坐標
android:pivotY
Float. 縮放中心點的y坐標
舉例如下:
首先展示一下動畫效果:
實現代碼如下:
首先通過xml定義一個縮放動畫(ScaleAnimation)排截,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<scale
android:duration="5000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.0"
android:toYScale="0.0" />
</set>
接著將上面定義的縮放動畫(ScaleAnimation)設置為ImageView的src嫌蚤,然后通過startAnimation播放動畫辐益,代碼如下:
ImageView對應的layout代碼同上,這里就不贅敘了脱吱。
loadAnimation = AnimationUtils.loadAnimation(getActivity(),
R.anim.base_animation_scale);
loadAnimation.setFillAfter(true);
image.startAnimation(loadAnimation);
TranslateAnimation(平移動畫)
上面語法中的<translate>標簽代表的就是平移動畫智政,顧名思義平移動畫就是通過不斷移動View的位置實現動畫的效果。
<translate>標簽相關屬性如下所示:
android:fromXDelta
Float or percentage. 移動起始點的x坐標. 表示形式有三種:
1 相對于自己的左邊界的距離箱蝠,單位像素值续捂。(例如 "5")
2 相對于自己的左邊界的距離與自身寬度的百分比。(例如 "5%")
3 相對于父View的左邊界的距離與父View寬度的百分比宦搬。(例如 "5%p")
android:toXDelta
Float or percentage. 移動結束點的x坐標. 表現形式同上
android:fromYDelta
Float or percentage. 移動起始點的y坐標. 表示形式有三種:
1 相對于自己的上邊界的距離牙瓢,單位像素值。(例如 "5")
2 相對于自己的上邊界的距離與自身高度的百分比间校。(例如 "5%")
3 相對于父View的上邊界的距離與父View高度的百分比矾克。(例如 "5%p")
android:toYDelta
Float or percentage. 移動結束點的y坐標. 表現形式同上
舉例如下:
首先展示一下動畫效果:
實現代碼如下:
首先通過xml定義一個平移動畫(TranslateAnimation),代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="2000"
android:fromXDelta="20"
android:fromYDelta="20"
android:toXDelta="100"
android:toYDelta="100" />
</set>
接著將上面定義的平移動畫(TranslateAnimation)設置為ImageView的src憔足,然后通過startAnimation播放動畫胁附,代碼如下:
ImageView對應的layout代碼同上,這里就不贅敘了四瘫。
loadAnimation = AnimationUtils.loadAnimation(getActivity(),
R.anim.base_aniamtion_translate);
loadAnimation.setFillAfter(true);
image.startAnimation(loadAnimation);
RotateAnimation(旋轉動畫)
上面語法中的<rotate>標簽代表的就是旋轉動畫汉嗽,顧名思義旋轉動畫就是通過不斷旋轉View實現動畫的效果。
<rotate>標簽相關屬性如下所示:
android:fromDegrees
Float. 旋轉初始的角度找蜜。
android:toDegrees
Float. 旋轉結束的角度饼暑。
android:pivotX
Float or percentage. 旋轉中心點x坐標,表示形式有三種:
1 相對于自己的左邊界的距離洗做,單位像素值弓叛。(例如 "5")
2 相對于自己的左邊界的距離與自身寬度的百分比。(例如 "5%")
3 相對于父View的左邊界的距離與父View寬度的百分比诚纸。(例如 "5%p")
android:pivotY
Float or percentage. 旋轉中心點y坐標撰筷,表示形式有三種:
1 相對于自己的上邊界的距離,單位像素值畦徘。(例如 "5")
2 相對于自己的上邊界的距離與自身寬度的百分比毕籽。(例如 "5%")
3 相對于父View的上邊界的距離與父View高度的百分比。(例如 "5%p")
舉例如下:
首先展示一下動畫效果:
實現代碼如下:
首先通過xml定義一個旋轉動畫(RotateAnimation)井辆,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<rotate
android:duration="1000"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="+360" />
</set>
接著將上面定義的旋轉動畫(RotateAnimation)設置為ImageView的src关筒,然后通過startAnimation播放動畫,代碼如下:
ImageView對應的layout代碼同上杯缺,這里就不贅敘了蒸播。
loadAnimation = AnimationUtils.loadAnimation(getActivity(),
R.anim.base_anmation_rotate);
image.startAnimation(loadAnimation);
補間動畫(Tween animation)兩個常用的特殊場景
1 通過布局動畫(LayoutAnimation)給ViewGroup的子View指定入場動畫。
舉例如下:
首先展示一下動畫效果:
實現代碼如下:
首先通過xml定義ViewGroup的子View入場動畫,代碼如下:
res/anim/zoom_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator" >
<scale
android:duration="500"
android:fromXScale="0.1"
android:fromYScale="0.1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
<alpha
android:duration="500"
android:fromAlpha="0"
android:toAlpha="1.0" />
</set>
接著為ListView設置布局動畫(LayoutAnimation)袍榆,代碼如下所示:
LayoutAnimationController lac=new LayoutAnimationController(AnimationUtils.loadAnimation(this, R.anim.zoom_in));
lac.setDelay(0.5f);
lac.setOrder(LayoutAnimationController.ORDER_RANDOM);
mListView.setLayoutAnimation(lac);
//mListView.startLayoutAnimation(); //可以通過該方法控制動畫在何時播放胀屿。
上面是通過java代碼來為ListView設置布局動畫(LayoutAnimation)的,其實通過xml也可以為ListView設置布局動畫(LayoutAnimation)包雀,代碼如下所示:
<ListView
android:id="@+id/listView"
android:layoutAnimation="@anim/anim_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
res/anim/anim_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="random"
android:animation="@anim/zoom_in"/>
2 通過補間動畫(Tween animation)為Activity自定義切換動畫
Android系統(tǒng)為Activity設置了默認的切換動畫宿崭,這個動畫我們是可以進行自定義的。通過調用Activity類的overridePendingTransition(int enterAnim, int exitAnim)方法可以實現自定義Activity的切換動畫才写,注意這個方法必須在startActivity和finish調用之后被調用劳曹,否者沒有效果。
Drawable動畫(逐幀動畫)
逐幀動畫是用來逐幀顯示預先定義好的一組圖片琅摩,類似于電影播放。對應于AnimationDrawable類锭硼。
FILE LOCATION:
res/drawable/filename.xml
The filename will be used as the resource ID.
COMPILED RESOURCE DATATYPE:
Resource pointer to an AnimationDrawable.
RESOURCE REFERENCE:
In Java: R.drawable.filename
In XML: @[package:]drawable.filename
不同于補間動畫房资,逐幀動畫資源文件放在drawable文件夾下。
語法:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] >
<item
android:drawable="@[package:]drawable/drawable_resource_name"
android:duration="integer" />
</animation-list>
<animation-list>標簽用來包含逐幀動畫的每一幀檀头。
<animation-list>標簽的相關屬性如下所示:
android:oneshot
Boolean. 當設置為true時動畫只會播放一次轰异,否者會循環(huán)播放。
<item>用來表示逐幀動畫的每一幀圖片暑始。
<item>標簽的相關屬性如下所示:
android:drawable
Drawable resource. 設置當前幀對應的Drawable 資源搭独。
android:duration
Integer. 設置顯示該幀的時間, 單位為毫秒(milliseconds)。
舉例如下:
首先展示一下動畫效果:
實現代碼如下:
首先通過xml定義一個逐幀動畫(AnimationDrawable)廊镜,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true" >
<item
android:drawable="@drawable/first_pic"
android:duration="1000"/>
<item
android:drawable="@drawable/second_pic"
android:duration="1000"/>
<item
android:drawable="@drawable/third_pic"
android:duration="1000"/>
<item
android:drawable="@drawable/fourth_pic"
android:duration="1000"/>
<item
android:drawable="@drawable/fifth_pic"
android:duration="1000"/>
<item
android:drawable="@drawable/sixth_pic"
android:duration="1000"/>
</animation-list>
然后將上面定義的AnimationDrawable作為View的背景并且通過AnimationDrawable來播放動畫牙肝,代碼如下:
image.setImageResource(R.drawable.anim_list);
AnimationDrawable animationDrawable = (AnimationDrawable) image.getDrawable();
animationDrawable.start();
//animationDrawable.stop(); //如果oneshot為false,必要時要停止動畫
上面是通過xml定義一個逐幀動畫嗤朴,也可以完全通過代碼來實現和上面相同效果配椭,如下所示:
//代碼定義、創(chuàng)建雹姊、執(zhí)行動畫
AnimationDrawable animationDrawable = new AnimationDrawable();
animationDrawable.addFrame(getResources().getDrawable(R.drawable.first_pic), 1000);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.second_pic), 1000);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.third_pic), 1000);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.fourth_pic), 1000);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.fifth_pic), 1000);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.sixth_pic), 1000);
animationDrawable.setOneShot(true);
image.setImageDrawable(animationDrawable);
animationDrawable.start();
注意:對于一些手機股缸,在Activity的onCreate()方法中調用AnimationDrawable的start()方法不起效果,可能是由于播放動畫的ImageView還沒有準備好吱雏,此時就需要在onCreate之后的生命周期的方法中調用敦姻,比如onResume方法。
屬性動畫框架
與屬性動畫相比View動畫存在一個缺陷歧杏,View動畫改變的只是View的顯示镰惦,而沒有改變View的響應區(qū)域,并且View動畫只能對View做四種類型的補間動畫得滤,因此Google在Android3.0及其后續(xù)版本中添加了屬性動畫框架陨献。同樣屬性動畫框架還提供了動畫集合類(AnimatorSet),通過動畫集合類(AnimatorSet)可以將多個屬性動畫以組合的形式顯示出來懂更。
下面是我關于屬性動畫框架工作原理的總結:
顧名思義只要某個類具有屬性(即該類含有某個字段的set和get方法)眨业,那么屬性動畫框架就可以對該類的對象進行動畫操作(其實就是通過反射技術來獲取和執(zhí)行屬性的get急膀,set方法),因此屬性動畫框架可以實現View動畫框架的所有動畫效果并且還能實現View動畫框架無法實現的動畫效果龄捡。屬性動畫框架工作原理可以總結為如下三步:
1 在創(chuàng)建屬性動畫時如果沒有設置屬性的初始值卓嫂,此時Android系統(tǒng)就會通過該屬性的get方法獲取初始值,所以在沒有設置屬性的初始值時聘殖,必須提供該屬性的get方法晨雳,否者程序會Crash。
2 在動畫播放的過程中奸腺,屬性動畫框架會利用時間流逝的百分比獲取屬性值改變的百分比(即通過時間插值器)餐禁,接著利用獲取的屬性值改變的百分比獲取改變后的屬性值(即通過類型估值器)。
3 通過該屬性的set方法將改變后的屬性值設置到對象中突照。
還要注意一點帮非,雖然通過set方法改變了對象的屬性值,但是還要將這種改變用動畫的形式表現出來讹蘑,否者就不會有動畫效果末盔,所以屬性動畫框架本身只是不斷的改變對象的屬性值并沒有實現動畫效果。
FILE LOCATION:
res/animator/filename.xml
The filename will be used as the resource ID.
COMPILED RESOURCE DATATYPE:
Resource pointer to a ValueAnimator, ObjectAnimator, or AnimatorSet.
RESOURCE REFERENCE:
In Java: R.animator.filename
In XML: @[package:]animator/filename
語法:
<set
android:ordering=["together" | "sequentially"]>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<animator
android:duration="int"
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>
在上面的語法中座慰,<set>對應AnimatorSet(屬性動畫集合)類陨舱,<objectAnimator>對應ObjectAnimator類,<animator>標簽對應ValueAnimator類版仔;并且屬性動畫集合還可以包含屬性動畫集合游盲。
<set>標簽相關屬性如下所示:
android:ordering
該屬性有如下兩個可選值:
together:表示動畫集合中的子動畫同時播放。
sequentially:表示動畫集合中的子動畫按照書寫的先后順序依次播放蛮粮。
該屬性的默認值是together背桐。
通過ObjectAnimator實現屬性動畫
<objectAnimator>標簽相關屬性如下所示:
android:propertyName
String. Required. 屬性動畫作用的屬性名稱
android:duration
int. 表示動畫的周期,默認值為300毫秒
android:valueFrom
float, int, or color. 表示屬性的初始值
android:valueTo
float, int, or color. Required. 表示屬性的結束值
android:startOffset
int. 表示調用start方法后延遲多少毫秒開始播放動畫
android:repeatCount
int. 表示動畫的重復次數蝉揍,-1代表無限循環(huán)链峭,默認值為0,表示動畫只播放一次又沾。
android:repeatMode
表示動畫的重復模式弊仪,該屬性有如下兩個可選值:
repeat:表示連續(xù)重復
reverse:表示逆向重復
android:valueType
Keyword. 表示android:propertyName所指定屬性的類型,有intType和floatType兩個可選項杖刷,
分別代表屬性的類型為整型和浮點型励饵,另外如果屬性是顏色值,那么就不需要指定
android:valueType屬性滑燃,Android系統(tǒng)會自動對顏色類型的屬性做處理役听。
默認值為floatType。
利用ObjectAnimator實現與補間動畫中4個實例相同的動畫效果,代碼如下:
//利用ObjectAnimator實現透明度動畫
ObjectAnimator.ofFloat(mImageView, "alpha", 1, 0, 1)
.setDuration(2000).start();
//利用AnimatorSet和ObjectAnimator實現縮放動畫
final AnimatorSet animatorSet = new AnimatorSet();
image.setPivotX(image.getWidth()/2);
image.setPivotY(image.getHeight()/2);
animatorSet.playTogether(
ObjectAnimator.ofFloat(image, "scaleX", 1, 0).setDuration(5000),
ObjectAnimator.ofFloat(image, "scaleY", 1, 0).setDuration(5000));
animatorSet.start();
//利用AnimatorSet和ObjectAnimator實現平移動畫
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofFloat(image, "translationX", 20, 100).setDuration(2000),
ObjectAnimator.ofFloat(image, "translationY", 20, 100).setDuration(2000));
animatorSet.start();
//利用ObjectAnimator實現旋轉動畫
image.setPivotX(image.getWidth()/2);
image.setPivotY(image.getHeight()/2);
ObjectAnimator.ofFloat(image, "rotation", 0, 360)
.setDuration(1000).start();
上面是通過代碼的形式實現的屬性動畫典予,對于通過xml定義屬性動畫的方式不是很常用甜滨,因為屬性的起始和結束值大多是在程序運行的時候動態(tài)獲取的。大家可以根據上面的語法自己嘗試一下瘤袖。
通過ValueAnimator實現屬性動畫
<animator>標簽相關屬性如下所示:
與<objectAnimator>標簽相比衣摩,除了沒有android:propertyName屬性和valueFrom 屬性是Required的之外,
其他的屬性都相同并且屬性的作用也一樣捂敌。
其實ValueAnimator類就是一個數值生成器艾扮,也就是沒有上面關于屬性動畫框架工作原理的第1步和第3步,ObjectAnimator作為ValueAnimator的子類占婉,實現了這兩步泡嘴。你只要給ValueAnimator提供一個初始值、結束值和周期時間逆济,ValueAnimator就會按照屬性動畫框架工作原理的第2步中的步驟生成具有一定規(guī)則的數字磕诊。
無法使用屬性動畫或者屬性動畫不起作用的情況和解決方法
無法使用屬性動畫或者屬性動畫不起作用的情況如下:
1 該字段沒有沒有set和get方法
2 該屬性的set方法僅僅改變了對象的屬性值,但是沒有將這種改變用動畫的形式表現出來
解決方法如下:
1 如果你又權限的話纹腌,給這個字段添加get和set方法,比如在自定義View中滞磺。
2 使用一個包裝類來封裝該字段對應的類升薯,間接為該字段提供get和set方法。
例如使ImageView從當前高度變化到600击困,代碼如下所示:
ViewWrapper viewWrapper = new ViewWrapper(mImageView);
ObjectAnimator.ofInt(viewWrapper, "height", 600).setDuration(5000).start();
public class ViewWrapper {
private View view;
public ViewWrapper(View view) {
this.view = view;
}
public int getHeight(){
return view.getLayoutParams().height;
}
public void setHeight(int height){
view.getLayoutParams().height = height;
view.requestLayout();
}
}
3 通過ValueAnimator實現動畫效果
舉例如下:
首先展示一下運行的效果:
實現代碼如下:
if (mBtHiddenView.getVisibility() == View.GONE) {
animateOPen(mBtHiddenView);
} else {
animateClose(mBtHiddenView);
}
private void animateOPen(final View view) {
view.setVisibility(View.VISIBLE);
ValueAnimator valueAnimator = createDropAnimator(view, 0, mHiddenViewHeight);
valueAnimator.setInterpolator(new AccelerateInterpolator());
valueAnimator.setDuration(1000).start();
}
private void animateClose(final View view) {
ValueAnimator valueAnimator = createDropAnimator(view, mHiddenViewHeight, 0);
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
view.setVisibility(View.GONE);
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(1000).start();
}
private ValueAnimator createDropAnimator(final View view, int start, int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(start, end);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// TODO Auto-generated method stub
LayoutParams params = view.getLayoutParams();
params.height = (int) animation.getAnimatedValue();
view.setLayoutParams(params);
}
});
return valueAnimator;
}
屬性動畫常用的特殊場景
1> 屬性動畫可以為ViewGroup的子View的顯示和隱藏設置過渡動畫涎劈。Android系統(tǒng)中已經提供了默認過渡動畫(在layout文件中將ViewGroup的animateLayoutChanges屬性打開就可以使用系統(tǒng)提供的默認過渡動畫)。Android系統(tǒng)中一共提供了如下所示的4種類型的過渡動畫:
APPEARING
當通過 設置子View的可見性為VISIBLE或者通過addView方法添加子View 來顯示子View時阅茶,
子View就會執(zhí)行該類型的動畫蛛枚。
該類型動畫的周期為300毫秒,默認延遲為300毫秒脸哀。
DISAPPEARING
當通過 設置子View的可見性為GONE或者通過removeView方法移除子View 來隱藏子View時蹦浦,
子View就會執(zhí)行該類型的動畫。
該類型動畫的周期為300毫秒撞蜂,默認延遲為0毫秒盲镶。
CHANGE_APPEARING
當顯示子View時,所有的兄弟View就會立即依次執(zhí)行該類型動畫并且兄弟View之間執(zhí)行動畫的間隙默認為0毫秒蝌诡,然后才會執(zhí)行顯示子View的動畫溉贿。
該類型動畫的周期為300毫秒,默認延遲為0毫秒浦旱。
CHANGE_DISAPPEARING
當隱藏子View的動畫執(zhí)行完畢后宇色,所有的兄弟View就會依次執(zhí)行該類型動畫并且兄弟View之間執(zhí)行動畫的間隙默認為0毫秒。
該類型動畫的周期為300毫秒,默認延遲為300毫秒宣蠕。
注意 上面描述的都是系統(tǒng)默認的行為例隆,我們可以做適當的改變。
如果感覺Android系統(tǒng)提供的過渡動畫不夠炫植影,你也可以自定義過渡動畫裳擎,下面就舉例說明一下如何自定義過渡動畫,首先展示一下效果圖:
布局相關代碼如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_add_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加圖片" />
<Button
android:id="@+id/btn_remove_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="移除圖片" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center_horizontal"
android:animateLayoutChanges="true"
android:orientation="vertical"/>
</LinearLayout>
在java代碼中為id為ll_image的LinearLayout設置自定義的過渡動畫思币,如下所示:
llImageView = (LinearLayout) root.findViewById(R.id.ll_image);
LayoutTransition transition = new LayoutTransition();
transition.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
transition.setDuration(LayoutTransition.CHANGE_APPEARING, transition.getDuration(LayoutTransition.CHANGE_APPEARING));
transition.setStartDelay(LayoutTransition.CHANGE_APPEARING, 0);
ObjectAnimator appearingAnimator = ObjectAnimator
.ofPropertyValuesHolder(
(Object) null,
PropertyValuesHolder.ofFloat("scaleX", 0.0f, 1.0f),
PropertyValuesHolder.ofFloat("scaleY", 0.0f, 1.0f),
PropertyValuesHolder.ofFloat("alpha", 0, 1.0f));
transition.setAnimator(LayoutTransition.APPEARING, appearingAnimator);
transition.setDuration(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.APPEARING));
transition.setStartDelay(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.CHANGE_APPEARING));
ObjectAnimator disappearingAnimator = ObjectAnimator
.ofPropertyValuesHolder(
(Object) null,
PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.0f),
PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.0f),
PropertyValuesHolder.ofFloat("alpha", 1.0f, 0));
transition.setAnimator(LayoutTransition.DISAPPEARING, disappearingAnimator);
transition.setDuration(LayoutTransition.DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING));
transition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
transition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);
transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, transition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING));
llImageView.setLayoutTransition(transition);
上面代碼依次對CHANGE_APPEARING鹿响、APPEARING、DISAPPEARING和CHANGE_DISAPPEARING類型的過渡動畫進行了設置谷饿,下面就來分析常用的設置方法:
setStagger方法
當多個子View要執(zhí)行同一個類型的動畫時惶我,就可以通過該方法來設置子View之間執(zhí)行動畫的間隙,
默認為0毫秒博投。
setAnimator方法
為指定類型的過渡動畫設置自定義的屬性動畫绸贡。
setDuration方法
為指定類型的過渡動畫設置執(zhí)行動畫的周期,默認為300毫秒毅哗。
setStartDelay方法
為指定類型的過渡動畫設置延遲執(zhí)行的時間听怕,默認與過渡動畫的類型相關,上面已經說過虑绵。
setLayoutTransition方法
為ViewGroup設置過渡動畫尿瞭。
經過上面代碼的設置后,LinearLayout顯示或者隱藏子View時就會執(zhí)行相關的過渡動畫翅睛,顯示或者隱藏子View的代碼如下所示:
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_add_image:{
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.drawable.second_pic);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200,200);
llImageView.addView(imageView, 0, layoutParams);
}
break;
case R.id.btn_remove_image:{
int count = llImageView.getChildCount();
if (count > 0) {
llImageView.removeViewAt(0);
}
}
break;
}
}
2> Vector(矢量圖)中的動畫
可以參考我的另外一篇blog Android中的矢量圖