技術學習記錄

[Android]轉載-Android樣式的開發:View Animation篇

轉載自Keegan小鋼

鏈接:http://keeganlee.me/post/android/20151003


drawable彙總篇講過兩個動畫,animation-list定義幀動畫,animated-rotate定義旋轉動畫,這兩個屬於drawable動畫。除了drawable動畫,Android框架還提供了另外兩種動畫體系:視圖動畫(View Animation)和屬性動畫(Property Animation)。視圖動畫比較簡單,只能應用於各種View,可以做一些位置、大小、旋轉和透明度的簡單轉變。屬性動畫則是在android 3.0引入的動畫體系,提供了更多特性和靈活性,也可以應用於任何對象,而不只是View。本篇先講視圖動畫。

視圖動畫可以通過xml文件定義,xml文件放於res/anim/目錄下,根元素可以為:<alpha>, <scale>, <translate>, <rotate>, 或者<set>。其中,<set>標籤定義的是動畫集,它可以包含多個其他標籤,也可以嵌套<set>標籤。默認情況下,所有動畫會同時播放;如果想按順序播放,則需要指定startOffset**屬性;另外,還可以通過設置interpolator改變動畫變化的速率,比如勻速、加速。

<alpha>

<alpha>可以實現透明度漸變的動畫效果,也就是淡入淡出的效果,可通過設置下面三個屬性來設置淡入或淡出效果:

  • 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));

如果需要重用這個動畫,也可以將其抽離出來。<alpha>標籤對應的動畫類為AlphaAnimation,父類為Animation,以上程式碼將AlphaAnimation抽離後的程式碼可以如下:

AlphaAnimation fadeInAnimation = (AlphaAnimation) AnimationUtils.loadAnimation(this, R.anim.fade_in);
view.startAnimation(fadeInAnimation);

<scale>

<scale>可以實現縮放的動畫效果,主要的屬性如下:

  • 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" />

<scale>標籤對應的類為ScaleAnimation,父類也是Animation,添加到View上的用法和AlphaAnimation一樣,程式碼如下:

ScaleAnimation zoomOutAnimation = (ScaleAnimation) AnimationUtils.loadAnimation(this, R.anim.zoom_out);
view.startAnimation(zoomOutAnimation);

<translate>

<translate>可以實現位置移動的動畫效果,可以是垂直方向的移動,也可以是水平方向的移動。坐標的值可以有三種格式:從-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" />

<translate>標籤對應的類為TranslateAnimation,父類也是Animation,添加到View上的程式碼如下:

TranslateAnimation moveAnimation = (TranslateAnimation) AnimationUtils.loadAnimation(this, R.anim.move_left_to_right);
view.startAnimation(moveAnimation);

<rotate>

<rotate>可以實現旋轉的動畫效果,主要的屬性如下:

  • 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%" />

<rotate>標籤對應的類為RotateAnimation,父類也是Animation,添加到View上的程式碼如下:

RotateAnimation rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation(this, R.anim.rotate_one);
view.startAnimation(rotateAnimation);

<set>

<set>標籤可以將多個動畫組合起來,變成一個動畫集。比如想將一張圖片縮放的同時也做移動,這時候就要用<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>, <scale>, <translate>, <rotate>這四種標籤,也可以嵌套其他<set>標籤。另外,<set>標籤可嵌套的標籤元素並不只有這幾個,後面談到屬性動畫時會再講其他的標籤及用法。

通用屬性

仔細觀察不難發現,以上五個標籤都有android:duration屬性,這是一個通用的屬性,而除了android:duration,還有其他的通用屬性,接下來看看都有哪些通用屬性以及相應的用法:

  • android:duration 動畫從開始到結束持續的時長,單位為毫秒
  • android:detachWallpaper 設置是否在壁紙上運行,只對設置了壁紙背景的窗口動畫(window animation)有效。設為true,則動畫只在窗口運行,壁紙背景保持不變
  • android:fillAfter 設置為true時,動畫執行完後,View會停留在動畫的最後一幀;默認為false;如果是動畫集,需在<set>標籤中設置該屬性才有效
  • android:fillBefore 設置為true時,動畫執行完後,View回到動畫執行前的狀態,默認即為true
  • android:fillEnabled 設置為true時,android:fillBefore的值才有效,否則android:fillBefore會被忽略
  • android:repeatCount 設置動畫重複執行的次數,默認為0,即不重複;可設為-1或infinite,表示無限重複
  • android:repeatMode 設置動畫重複執行的模式,可設為以下兩個值其中之一:
    • restart 動畫重複執行時從起點開始,默認為該值
    • reverse 動畫會反方向執行
  • android:startOffset 設置動畫執行之前的等待時長,毫秒為單位;重複執行時,每次執行前同樣也會等待一段時間
  • android:zAdjustment 表示被設置動畫的內容在動畫運行時在Z軸上的位置,取值為以下三個值之一:
    • normal 默認值,保持內容在Z軸上的位置不變
    • top 保持在Z周最上層
    • bottom 保持在Z軸最下層
  • android:interpolator 設置動畫速率的變化,比如加速、減速、勻速等,需要指定Interpolator資源,後面再詳細講解

PS:<set>標籤還有個android:shareInterpolator**屬性,設置為true時則可將interpolator應用到所有子元素中

Interpolator

通過interpolator可以定義動畫速率變化的方式,比如加速、減速、勻速等,每種interpolator都是 Interpolator 類的子類,Android系統已經實現了多種interpolator,對應也提供了公共的資源ID,如下表:

Interpolator class Resource ID Description
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/bounce_interpolator 動畫循環做週期運動,速率改變沿著正弦曲線
DecelerateInterpolator @android:anim/decelerate_interpolator 在動畫開始時速率改變比較快,然後開始減速
LinearInterpolator @android:anim/decelerate_interpolator 動畫勻速播放
OvershootInterpolator @android:anim/overshoot_interpolator 動畫向前拋,會拋超過最後值,然後再返回

如果系統提供的以上Interpolator還不符合你的效果,也可以自定義。自定義的方式有兩種,一種是通過繼承 Interpolator 父類或其子類;另一種是通過自定義的xml文件,可以更改上表中Interpolator的屬性。自定義的xml文件需存放於res/anim/目錄下,根標籤與上表相應的有九種如下:

  • <accelerateDecelerateInterpolator> 在動畫開始與結束時速率改變比較慢,在中間的時候加速。沒有可更改設置的屬性,所以設置的效果和系統提供的一樣
  • <accelerateInterpolator> 在動畫開始時速率改變比較慢,然後開始加速。有一個屬性可以設置加速的速率
    • android:factor 浮點值,加速的速率,默認為1
  • <anticipateInterpolator> 動畫開始的時候向後然後往前拋。有一個屬性設置向後拉的值
    • android:tension 浮點值,向後的拉力,默認為2,當設為0時,則不會有向後的動畫了
  • <anticipateOvershootInterpolator> 動畫開始的時候向後然後向前拋,會拋超過目標值後再返回到最後的值。可設置兩個屬性
    • android:tension 浮點值,向後的拉力,默認為2,當設為0時,則不會有向後的動畫了
    • android:extraTension 浮點值,拉力的倍數,默認為1.5(2*1.5),當設為0時,則不會有拉力了
  • <bounceInterpolator> 動畫結束的時候會彈跳。沒有可更改設置的屬性
  • <cycleInterpolator> 動畫循環做週期運動,速率改變沿著正弦曲線。有一個屬性設置循環次數
    • android:cycles 整數值,循環的次數,默認為1
  • <decelerateInterpolator> 在動畫開始時速率改變比較快,然後開始減速。有一個屬性設置減速的速率
    • android:factor 浮點值,減速的速率,默認為1
  • <linearInterpolator> 動畫勻速播放。沒有可更改設置的屬性
  • <overshootInterpolator> 動畫向前拋,會拋超過最後值,然後再返回。有一個屬性
    • android:tension 浮點值,超出終點後的拉力,默認為2

具體用法,就舉個示例吧,先定義個interpolator的xml文件,程式碼如下:

<!-- res/anim/my_interpolator.xml -->
<?xml version="1.0" encoding="utf-8"?>
<anticipateOvershootInterpolator 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:tension="3"
    android:extraTension="2" />

接著,將其設置到要應用的動畫的android:interpolator屬性即可,程式碼如下:

<!-- 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%"
    android:interpolator="@anim/my_interpolator" />

寫在最後

視圖動畫的應用主要就這些了,比較簡單,當然也有其侷限性。比如只能應用於View,也只能做漸變、縮放、旋轉和移動,以及這些動畫的組合。下一篇再詳細講解屬性動畫,屬性動畫可以輕而易舉的做到許多視圖動畫做不到的事,比如說圖片的翻轉。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *