Android動畫的理解
基礎知識
在我們開始講Android動畫這個知識點之前,我們了解下相應的基礎知識點。
Shape篇
一般用Shape定義的XML文件是存放在Drawable目錄下,廣泛應用于在Button、TextView、EditText等各種基本控件中,來實現不同背景、顏色、邊框。
使用Shape可以自定義形狀,可以定義下面四種類型的形狀,通過android:shape屬性指定:
- rectangle:矩形,默認的形狀
- oval:橢圓形,可以畫正圓
- line:線形,可以畫實線和虛線
- ring:環形,可以話進度條之類
rectange
- solid : 設置形狀填充的顏色,只有android:color一個屬性
- android:color 填充的顏色
- padding : 設置內容與形狀邊界的內間距,可分別設置左右上下的距離
- android:left 左內間距
- android:right 右內間距
- android:top 上內間距
- android:bottom 下內間距
- gradient : 設置形狀的漸變顏色,可以是線性漸變、輻射漸變、掃描性漸變
- android:type 漸變的類型 linear 線性漸變,默認的漸變類型 radial 放射漸變,設置該項時,android:gradientRadius也必須設置 sweep 掃描性漸變
- android:startColor 漸變開始的顏色
- android:endColor 漸變結束的顏色
- android:centerColor 漸變中間的顏色
- android:angle 漸變的角度,線性漸變時才有效,必須是45的倍數,0表示從左到右,90表示從下到上
- android:centerX 漸變中心的相對X坐標,放射漸變時才有效,在0.0到1.0之間,默認為0.5,表示在正中間
- android:centerY 漸變中心的相對X坐標,放射漸變時才有效,在0.0到1.0之間,默認為0.5,表示在正中間
- android:gradientRadius 漸變的半徑,只有漸變類型為radial時才使用
- android:useLevel 如果為true,則可在LevelListDrawable中使用
- corners : 設置圓角,只適用于rectangle類型,可分別設置四個角不同半徑的圓角,當設置的圓角半徑很大時,比如200dp,就可變成弧形邊了
- android:radius 圓角半徑,會被下面每個特定的圓角屬性重寫
- android:topLeftRadius 左上角的半徑
- android:topRightRadius 右上角的半徑
- android:bottomLeftRadius 左下角的半徑
- android:bottomRightRadius 右下角的半徑
- stroke : 設置描邊,可描成實線或虛線。
- android:color 描邊的顏色
- android:width 描邊的寬度
- android:dashWidth 設置虛線時的橫線長度
- android:dashGap 設置虛線時的橫線之間的距離
oval
它也有solid、padding、stroke、gradient、size幾個特性,size是用來設置形狀大小的,如下:
size: 設置形狀默認的大小,可設置寬度和高度
android:width 寬度
android:height 高度
line
畫線時,有幾點特性必須要知道的:
- 只能畫水平線,畫不了豎線;
- 線的高度是通過stroke的android:width屬性設置的;
- size的android:height屬性定義的是整個形狀區域的高度;
- size的height必須大于stroke的width,否則,線無法顯示;
- 線在整個形狀區域中是居中顯示的;
- 線左右兩邊會留有空白間距,線越粗,空白越大;
- 引用虛線的view需要添加屬性android:layerType,值設為"software",否則顯示不了虛線。
ring
首先,shape根元素有些屬性只適用于ring類型,先過目下這些屬性吧:
- android:innerRadius 內環的半徑
- android:innerRadiusRatio 浮點型,以環的寬度比率來表示內環的半徑,默認為3,表示內環半徑為環的寬度除以3,該值會被android:innerRadius覆蓋
- android:thickness 環的厚度
- android:thicknessRatio 浮點型,以環的寬度比率來表示環的厚度,默認為9,表示環的厚度為環的寬度除以9,該值會被android:thickness覆蓋
- android:useLevel 一般為false,否則可能環形無法顯示,只有作為LevelListDrawable使用時才設為true
Selector篇
shape只能定義單一的形狀,而實際應用中,很多地方比如按鈕、Tab、ListItem等都是不同狀態有不同的展示形狀。舉個例子,一個按鈕的背景,默認時是一個形狀,按下時是一個形狀,不可操作時又是另一個形狀。有時候,不同狀態下改變的不只是背景、圖片等,文字顏色也會相應改變。而要處理這些不同狀態下展示什么的問題,就要用selector來實現了。
那么,看看都有哪些狀態可以設置呢:
- android:state_enabled : 設置觸摸或點擊事件是否可用狀態,一般只在false時設置該屬性,表示不可用狀態
- android:state_pressed : 設置是否按壓狀態,一般在true時設置該屬性,表示已按壓狀態,默認為false
- android:state_selected : 設置是否選中狀態,true表示已選中,false表示未選中
- android:state_checked : 設置是否勾選狀態,主要用于CheckBox和RadioButton,true表示已被勾選,false表示未被勾選
- android:state_checkable : 設置勾選是否可用狀態,類似state_enabled,只是state_enabled會影響觸摸或點擊事件,而state_checkable影響勾選事件
- android:state_focused : 設置是否獲得焦點狀態,true表示獲得焦點,默認為false,表示未獲得焦點
- android:state_window_focused : 設置當前窗口是否獲得焦點狀態,true表示獲得焦點,false表示未獲得焦點,例如拉下通知欄或彈出對話框時,當前界面就會失去焦點;另外,ListView的ListItem獲得焦點時也會觸發true狀態,可以理解為當前窗口就是ListItem本身
- android:state_activated : 設置是否被激活狀態,true表示被激活,false表示未激活,API Level 11及以上才支持,可通過代碼調用控件的setActivated(boolean)方法設置是否激活該控件
- android:state_hovered : 設置是否鼠標在上面滑動的狀態,true表示鼠標在上面滑動,默認為false,API Level 14及以上才支持
Layer-List篇
使用layer-list可以將多個drawable按照順序層疊在一起顯示。
帶陰影的圓角矩形
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 灰色陰影 -->
<item
android:left="2dp"
android:top="4dp">
<shape>
<solid android:color="@android:color/darker_gray" />
<corners android:radius="10dp" />
</shape>
</item>
<!-- 白色前景 -->
<item
android:bottom="4dp"
android:right="2dp">
<shape>
<solid android:color="#FFFFFF" />
<corners android:radius="10dp" />
</shape>
</item>
</layer-list>
從上面的示例代碼可以看到,layer-list可以作為根節點,也可以作為selector中item的子節點。layer-list可以添加多個item子節點,每個item子節點對應一個drawable資源,按照item從上到下的順序疊加在一起,再通過設置每個item的偏移量就可以看到陰影等效果了。layer-list的item可以通過下面四個屬性設置偏移量:
- android:top 頂部的偏移量
- android:bottom 底部的偏移量
- android:left 左邊的偏移量
- android:right 右邊的偏移量
這四個偏移量和控件的margin設置差不多,都是外間距的效果。如何不設置偏移量,前面的圖層就完全擋住了后面的圖層,從而也看不到后面的圖層效果了。
另外,關于item的用法,也做下總結:
- 根節點不同時,可設置的屬性是會不同的,比如selector下,可以設置一些狀態屬性,而在layer-list下,可以設置偏移量;
- 就算父節點同樣是selector,放在drawable目錄和放在color目錄下可用的屬性也會不同,比如drawable目錄下可用的屬性為android:drawable,在color目錄下可用的屬性為android:color;
- item的子節點可以為任何類型的drawable類標簽,除了上面例子中的shape、color、layer-list,也可以是selector,還有其他沒講過的bitmap、clip、scale、inset、transition、rotate、animated-rotate、lever-list等等。
Drawable資源篇
nine-patch標簽
使用nine-patch標簽可以對點九圖片做一些設置處理,不過可設置的屬性并不多:
- android:src 必填項,必須指定點九類型的圖片
- android:dither 設置是否抖動,圖片與屏幕的像素配置不同時會用到,比如圖片是ARGB 8888的,而屏幕是RGB565
- android:tint 給圖片著色,比如圖片本來是黑色的,著色后可以變成白色
- android:tintMode 著色模式,API Level 21(Android 5.0)才添加的屬性
- android:alpha 設置圖片的透明度,取值范圍為0.0~1.0之間,0.0為全透明,1.0為全不透明,API Level最低要求是11
- android:autoMirrored 設置圖片是否需要鏡像反轉,當布局方向是RTL,即從右到左布局時才有用,API Level 19(Android 4.4)才添加的屬性
scale標簽
使用scale標簽可以對drawable進行縮放操作,和clip一樣是通過設置level來控制縮放的比例。scale標簽可以設置的屬性如下:
- android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標簽
- android:scaleHeight 設置可縮放的高度,用百分比表示,格式為XX%,0%表示不做任何縮放,50%表示只能縮放一半
- android:scaleWidth 設置可縮放的寬度,用百分比表示,格式為XX%,0%表示不做任何縮放,50%表示只能縮放一半
- android:scaleGravity 設置drawable縮放后的位置,取值和bitmap標簽的一樣,就不一一列舉說明了,不過默認值是left
- android:useIntrinsicSizeAsMinimum 設置drawable原有尺寸作為最小尺寸,設為true時,縮放基本無效,API Level最低要求為11
rotate標簽
使用rotate標簽可以對一個drawable進行旋轉操作,在 shape篇 講環形時最后舉了個進度條時就用到了rotate標簽。另外,比如你有一張箭頭向上的圖片,但你還需要一個箭頭向下的圖片,這時就可以使用rotate將向上的箭頭旋轉變成一張箭頭向下的drawable。
先看看rotate標簽的一些屬性吧:
- android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標簽
- android:fromDegrees 起始的角度度數
- android:toDegrees 結束的角度度數,正數表示順時針,負數表示逆時針
- android:pivotX 旋轉中心的X坐標,浮點數或是百分比。浮點數表示相對于drawable的左邊緣距離
Drawable Animation
引用官方文檔的話
Drawable animation lets you load a series of Drawable resources one after another to create an animation. This is a traditional animation in the sense that it is created with a sequence of different images, played in order, like a roll of film.
其實說明動畫的Drawable的資源按照一定順序執行,最終出來的效果類似電影中一幀一幀的,它允許你實現像播放幻燈片一樣的效果。
是它的根元素,做為根節點,下面就是一個例子
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
<item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
<item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>
這里定義了三個drawable資源文件,每次執行時間為200ms,順序是從上到下,這種動畫最常見應用場景是在想表達電池充電的過程,從0%,25%,50%,100%表達連續充電的過程,就可以做四個不同的資源圖片,然后按照一定的順序,進而執行相應的運行時間。
有了動畫文件之后,具體怎么用呢,如下:
AnimationDrawable rocketAnimation;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
rocketAnimation.start();
return true;
}
return super.onTouchEvent(event);
}</code></pre>
特別注意,AnimationDrawable的start()方法不能在Activity的onCreate方法中調運,因為AnimationDrawable還未完全附著到window上,所以最好的調運時機是onWindowFocusChanged()方法中。
其中Drawable Animation還有一個 animated-rotate 屬性來定義旋轉動畫,這個用法也是類似的,不再過多講述。
View Animation
引用官方文檔
You can use the view animation system to perform tweened animation on Views. Tween animation calculates the animation with information such as the start point, end point, size, rotation, and other common aspects of an animation.
視圖動畫,也叫Tween(補間)動畫可以在一個視圖容器內執行一系列簡單變換(位置、大小、旋轉、透明度)。譬如,如果你有一個TextView對象,您可以移動、旋轉、縮放、透明度設置其文本,當然,如果它有一個背景圖像,背景圖像會隨著文本變化。
補間動畫通過XML或Android代碼定義,建議使用XML文件定義,因為它更具可讀性、可重用性。
Animation控制的是整個View,實現的原理是每次繪制視圖時,View所在的ViewGroup的drawChild函數獲取該View的Animation的Transformation值,然后調用canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀。如果動畫沒完成,就繼續調用invalidate()函數,啟動下次繪制來驅動動畫,從而完成整個動畫的繪制。
視圖動畫使用簡單,主要有以下四種類型動畫:
- Alpha Animation
- Rotate Animation
- Translate Animation
- Scale Animation
并提供了AnimationSet動畫集合,混合使用多種動畫方式,在Android 3.0之前,View Animation一家獨大,但是隨著Property Animation的推出,風光就大不如前,相比屬性動畫,視圖動畫一個最大的缺陷是不具備交互性,當某個元素發生視圖動畫后,其響應的事件的位置還依然在動畫前的地方,所以視圖動畫只能做普通的動畫效果,避免交互的發生,但它的優點是,效率高而且使用方便。
Alpha Animation
可以實現透明度漸變的動畫效果,也就是淡入淡出的效果,可通過設置下面三個屬性來設置淡入或淡出效果:
- android:duration 動畫從開始到結束持續的時長,單位為毫秒
- android:fromAlpha 動畫開始時的透明度,0.0為全透明,1.0為不透明,默認為1.0
- android:toAlpha 動畫結束時的透明度,0.0為全透明,1.0為不透明,默認為1.0
當設置開始時透明度為0.0,結束時為1.0,就能實現淡入效果;相反,當設置開始時透明度為1.0,結束時為0.0,那就能實現淡出效果。示例代碼如下:
<!-- res/anim/fade_in.xml -->
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
將這動畫效果添加到View上也只需要一行代碼:
view.startAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_in));
將這動畫效果添加到View上也只需要一行代碼:
Rotate Animation
可以實現旋轉的動畫效果,主要的屬性如下:
- android:duration 動畫從開始到結束持續的時長,單位為毫秒
- android:fromDegrees 旋轉開始的角度
- android:toDegrees 旋轉結束的角度
- android:pivotX 旋轉中心點的X坐標,純數字表示相對于View本身左邊緣的像素偏移量;帶"%"后綴時表示相對于View本身左邊緣的百分比偏移量;帶"%p"后綴時表示相對于父View左邊緣的百分比偏移量
- android:pivotY 旋轉中心點的Y坐標,純數字表示相對于View本身頂部邊緣的像素偏移量;帶"%"后綴時表示相對于View本身頂部邊緣的百分比偏移量;帶"%p"后綴時表示相對于父View頂部邊緣的百分比偏移量
以下示例代碼旋轉角度從0到360,即旋轉了一圈,旋轉的中心點都設為了50%,即是View本身中點的位置。
<!-- res/anim/rotate_one.xml -->
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%" />
標簽對應的類為RotateAnimation,父類也是Animation,添加到View上的代碼如下:
RotateAnimation rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation(this, R.anim.rotate_one);
view.startAnimation(rotateAnimation);
Translate Animation
可以實現位置移動的動畫效果,可以是垂直方向的移動,也可以是水平方向的移動。坐標的值可以有三種格式:從-100到100,以"%"結束,表示相對于View本身的百分比位置;如果以"%p"結束,表示相對于View的父View的百分比位置;如果沒有任何后綴,表示相對于View本身具體的像素值。主要的屬性如下:
- android:duration 動畫從開始到結束持續的時長,單位為毫秒
- android:fromXDelta 起始位置的X坐標的偏移量
- android:toXDelta 結束位置的X坐標的偏移量
- android:fromYDelta 起始位置的Y坐標的偏移量
- android:toYDelta 結束位置的Y坐標的偏移量
看示例吧,以下代碼實現的是從左到右的移動效果,起始位置為相對于控件本身-100%的位置,即在控件左邊,與控件本身寬度一致的位置;結束位置為相對于父控件100%的位置,即會移出父控件右邊緣的位置。
<!-- res/anim/move_left_to_right.xml -->
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromXDelta="-100%"
android:fromYDelta="0"
android:toXDelta="100%p"
android:toYDelta="0" />
標簽對應的類為TranslateAnimation,父類也是Animation,添加到View上的代碼如下:
TranslateAnimation moveAnimation = (TranslateAnimation) AnimationUtils.loadAnimation(this, R.anim.move_left_to_right);
view.startAnimation(moveAnimation);
Scale Animation
可以實現縮放的動畫效果,主要的屬性如下:
- android:duration 動畫從開始到結束持續的時長,單位為毫秒
- android:fromXScale 動畫開始時X坐標上的縮放尺寸
- android:toXScale 動畫結束時X坐標上的縮放尺寸
- android:fromYScale 動畫開始時Y坐標上的縮放尺寸
- android:toYScale 動畫結束時Y坐標上的縮放尺寸
PS : 以上四個屬性,0.0表示縮放到沒有,1.0表示正常無縮放,小于1.0表示收縮,大于1.0表示放大
- android:pivotX 縮放時的固定不變的X坐標,一般用百分比表示,0%表示左邊緣,100%表示右邊緣
- android:pivotY 縮放時的固定不變的Y坐標,一般用百分比表示,0%表示頂部邊緣,100%表示底部邊緣
具體示例:
<!-- res/anim/zoom_out.xml -->
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="0%"
android:pivotY="100%"
android:toXScale="1.5"
android:toYScale="1.5" />
對應的類為ScaleAnimation,父類也是Animation,添加到View上的用法和AlphaAnimation一樣,代碼如下:
ScaleAnimation zoomOutAnimation = (ScaleAnimation) AnimationUtils.loadAnimation(this, R.anim.zoom_out);
view.startAnimation(zoomOutAnimation);
Set Animation
標簽可以將多個動畫組合起來,變成一個動畫集。比如想將一張圖片縮放的同時也做移動,這時候就要用set標簽組合縮放動畫和移動動畫了。示例代碼如下:
<!-- res/anim/move_and_scale.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000">
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="200%"
android:toYDelta="0" />
<scale
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="0%"
android:pivotY="100%"
android:toXScale="1.5"
android:toYScale="1.5" />
</set>
以上代碼實現的動畫效果為向右移動的同時也同步放大。Set標簽在視圖動畫中除了可以組合Alpha ,Rotate , Scale , Scale 這四種標簽,也可以嵌套其他Set標簽。
Property Animation
引用官方文檔
The property animation system is a robust framework that allows you to animate almost anything. You can define an animation to change any object property over time, regardless of whether it draws to the screen or not. A property animation changes a property's (a field in an object) value over a specified length of time. To animate something, you specify the object property that you want to animate, such as an object's position on the screen, how long you want to animate it for, and what values you want to animate between
視圖動畫只能作用于View,而且視圖動畫改變的只是View的繪制效果,View真正的屬性并沒有改變。比如,一個按鈕做平移的動畫,雖然按鈕的確做了平移,但按鈕可點擊的區域并沒隨著平移而改變,還是在原來的位置。而屬性動畫則可以改變真正的屬性,從而實現按鈕平移時點擊區域也跟著平移。通俗點說,屬性動畫其實就是在一定時間內,按照一定規律來改變對象的屬性,從而使對象展現出動畫效果。
屬性動畫是在android 3.0引入的動畫體系,如果還想適配基本已經滅絕的2.x版本,只好繞道了。
屬性動畫和視圖動畫一樣,可以通過xml文件定義,不同的是,視圖動畫的xml文件放于 res/anim/ 目錄下,而屬性動畫的xml文件則放于 res/animator/ 目錄下。一個是 anim ,一個是 animator ,別搞錯了。同樣的,在Java代碼里引用屬性動畫的xml文件時,則用 R.animator.filename ,不同于視圖動畫,引用時為 R.anim.filename 。
屬性動畫主要有三個元素: animator , objectAnimator , set
相對應的有三個類: ValueAnimator 、 ObjectAnimator 、 AnimatorSet 。
ValueAnimator是基本的動畫類,處理值動畫,通過監聽某一值的變化,進行相應的操作。 ObjectAnimator 是 ValueAnimator 的子類,處理對象動畫。 AnimatorSet 則為動畫集,可以組合另外兩種動畫或動畫集。相應的三個標簽元素的關系也一樣。
樣式開發主要還是用xml的形式,所以這里先主要還是講標簽的用法。
animator
animator標簽與對應的 ValueAnimator 類提供了屬性動畫的核心功能,包括計算動畫值、動畫時間細節、是否重復等。執行屬性動畫分兩個步驟:
- 計算動畫值
- 將動畫值應用到對象和屬性上
ValuAnimiator只完成第一步,即只計算值,要實現第二步則需要在值變化的監聽器里自行更新對象屬性。
通過animator標簽可以很方便的對 ValuAnimiator 進行設置,可設置的屬性如下:
- android:duration 動畫從開始到結束持續的時長,單位為毫秒
- android:startOffset 設置動畫執行之前的等待時長,單位為毫秒
- android:repeatCount 設置動畫重復執行的次數,默認為0,即不重復;可設為-1或infinite,表示無限重復
- android:repeatMode 設置動畫重復執行的模式,可設為以下兩個值其中之一:
- restart 動畫重復執行時從起點開始,默認為該值
- reverse 動畫會反方向執行
- android:valueFrom 動畫開始的值,可以為int值、float值或color值
- android:valueTo 動畫結束的值,可以為int值、float值或color值
- android:valueType 動畫值類型,若為color值,則無需設置該屬性
- intType 指定動畫值,即以上兩個value屬性的值為整型
- floatType 指定動畫值,即以上兩個value屬性的值為浮點型,默認值
- android:interpolator 設置動畫速率的變化,比如加速、減速、勻速等,需要指定Interpolator資源。
接著,用一個實例講解具體的用法吧。在這個例子里,將一個按鈕的寬度進行縮放,從100%縮放到20%。
xml文件的代碼如下:
<!-- res/animator/value_animator.xml -->
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:valueFrom="100"
android:valueTo="20"
android:valueType="intType" />
可看到,值的變化從100到20,動畫時長3000毫秒,以下則是目標按鈕的xml代碼:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_btn_normal"
android:onClick="onScaleWidth"
android:text="點我"
android:textColor="@android:color/white" />
按鈕默認是填充屏幕寬度的,點擊時的執行方法為onScaleWidth,以下則是onScaleWidth方法的代碼:
public void onScaleWidth(final View view) {
// 獲取屏幕寬度
final int maxWidth = getWindowManager().getDefaultDisplay().getWidth();
ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.value_animator);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
// 當前動畫值,即為當前寬度比例值
int currentValue = (Integer) animator.getAnimatedValue();
// 根據比例更改目標view的寬度
view.getLayoutParams().width = maxWidth * currentValue / 100;
view.requestLayout();
}
});
valueAnimator.start();
}
從中,我們可以看到屬性動畫則是通過 AnimatorInflater 類的 loadAnimation() 方法獲取相應的 Animator 類實例。另外, ValueAnimator 通過添加AnimatorUpdateListener監聽器監聽值的變化,從而再手動更新目標對象的屬性。最后,通過調用 valueAnimator.start() 方法啟動動畫。
objectAnimator
objectAnimator標簽對應的類為ObjectAnimator,為 ValueAnimator 的子類。objectAnimator標簽與標簽animator不同的是,可以直接指定動畫的目標對象的屬性。標簽可設置的屬性除了和一樣的那些,另外多了一個:
- android:propertyName 目標對象的屬性名,要求目標對象必須提供該屬性的setter方法,如果動畫的時候沒有初始值,還需要提供getter方法
還是用實例說明具體用法,還是用上面的例子,將一個按鈕的寬度進行縮放,從100%縮放到20%,但這次改用objectAnimator實現。
<!-- res/animator/object_animator.xml -->
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="width"
android:valueFrom="100"
android:valueTo="20"
android:valueType="intType" />
與上面animator標簽方式做對比,就只是多了一個 android:propertyName 的屬性,設置值為width。也就是說,動畫改變的屬性為width,值將從100逐漸減到20。另外,值是從setWidth()傳遞過去的,再從getWidth()獲取。而且,這里設置的值代表的是比例值,因此,還需要進行計算轉化為實際的寬度值。最后,對象實際的寬度值為 view.getLayoutParams().width 。因此,需要用一個包裝類來包裝原始的view對象,對其提供setWidth()和getWidth()方法,代碼如下:
private static class ViewWrapper {
private View target; //目標對象
private int maxWidth; //最長寬度值
public ViewWrapper(View target, int maxWidth) {
this.target = target;
this.maxWidth = maxWidth;
}
public int getWidth() {
return target.getLayoutParams().width;
}
public void setWidth(int widthValue) {
//widthValue的值從100到20變化
target.getLayoutParams().width = maxWidth * widthValue / 100;
target.requestLayout();
}
}</code></pre>
上面setWidth()的代碼里,根據比例值轉化為了實際的寬度值。最后,動畫處理的代碼如下:
public void onScaleWidth(View view) {
// 獲取屏幕寬度
int maxWidth = getWindowManager().getDefaultDisplay().getWidth();
// 將目標view進行包裝
ViewWrapper wrapper = new ViewWrapper(view, maxWidth);
// 將xml轉化為ObjectAnimator對象
ObjectAnimator objectAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.object_animator);
// 設置動畫的目標對象為包裝后的view
objectAnimator.setTarget(wrapper);
// 啟動動畫
objectAnimator.start();
}
ObjectAnimator提供了屬性的設置,但相應的需要有該屬性的setter和getter方法。而 ValueAnimator 則只是定義了值的變化,并不指定目標屬性,所以也不需要提供setter和getter方法,但只能在AnimatorUpdateListener監聽器里手動更新屬性。不過,也因為沒有指定屬性,所以其實更具靈活性了,你可以在監聽器里根據值的變化做任何事情,比如更新多個屬性,比如在縮放寬度的同時做垂直移動。
為了對View更方便的設置屬性動畫,Android系統也提供了View的一些屬性和相應的setter和getter方法:
- alpha :透明度,默認為1,表示不透明,0表示完全透明
- pivotX 和 pivotY :旋轉的軸點和縮放的基準點,默認是View的中心點
- scaleX 和 scaleY :基于pivotX和pivotY的縮放,1表示無縮放,小于1表示收縮,大于1則放大
- rotation 、 rotationX 和 rotationY :基于軸點(pivotX和pivotY)的旋轉,rotation為平面的旋轉,rotationX和rotationY為立體的旋轉
- translationX 和 translationY :View的屏幕位置坐標變化量,以layout容器的左上角為坐標原點
- x 和 y :View在父容器內的最終位置,是左上角坐標和偏移量(translationX,translationY)的和
set
set標簽對應于 AnimatorSet 類,可以將多個動畫組合成一個動畫集,如上面提到的在縮放寬度的同時做垂直移動,可以將一個縮放寬度的動畫和一個垂直移動的動畫組合在一起。
set標簽有一個屬性可以設置動畫的時序關系:
- android:ordering 設置動畫的時序關系,取值可為以下兩個值之一: together 動畫同時執行,默認值 sequentially 動畫按順序執行
那如果想有些動畫同時執行,有些按順序執行,該怎么辦呢?因為set標簽是可以嵌套其他set標簽的,也就是說可以將同時執行的組合在一個set標簽,再嵌在按順序執行的set標簽內。
<!-- res/animator/animator_set.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="3000"
android:propertyName="width"
android:valueFrom="100"
android:valueTo="20"
android:valueType="intType" />
<objectAnimator
android:duration="3000"
android:propertyName="marginTop"
android:valueFrom="0"
android:valueTo="100"
android:valueType="intType" />
</set>
以上代碼可實現兩個同時執行的動畫,一個將width從100縮放到20,一個將marginTop從0增加到100。多了一個marginTop屬性,那么,在ViewWrapper添加setMarginTop()方法,添加后的ViewWrapper類代碼如下:
private static class ViewWrapper {
private View target;
private int maxWidth;
public ViewWrapper(View target, int maxWidth) {
this.target = target;
this.maxWidth = maxWidth;
}
public int getWidth() {
return target.getLayoutParams().width;
}
public void setWidth(int widthValue) {
target.getLayoutParams().width = maxWidth * widthValue / 100;
target.requestLayout();
}
public void setMarginTop(int margin) {
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) target.getLayoutParams();
layoutParams.setMargins(0, margin, 0, 0);
target.setLayoutParams(layoutParams);
}
}</code></pre>
最后,動畫處理的代碼:
public void onScaleWidth(View view) {
// 獲取屏幕寬度
int maxWidth = getWindowManager().getDefaultDisplay().getWidth();
// 將目標view進行包裝
ViewWrapper wrapper = new ViewWrapper(view, maxWidth);
// 將xml轉化為ObjectAnimator對象
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.animator_set);
// 設置動畫的目標對象為包裝后的view
animatorSet.setTarget(wrapper);
// 啟動動畫
animatorSet.start();
}
這樣就實現了寬度縮放和垂直移動的效果。
當然,在Android3.0之后,Google給View增加了animate方法來直接驅動屬性動畫,代碼如下:
view.animate().x(50f).y(100f);
小結
目前到此為止,我們了解到在Android中有三種不同的動畫類型,在Android3.0版本其實是一個區分點,在3.0之前用的居多都是View Animation,而在3.0之后用的居多是Property Animation,本次介紹的是這三者之間的區別和不同用法。
來自:http://www.cnblogs.com/cr330326/p/6062032.html