1. 什麼是 Tween Animation?
通過 Animation 物件在影象上執行一系列的變換而形成的動畫。
Creates an animation by performing a series of transformations on a single image with an Animation
2. Tween Animation 的作用是什麼?
通過上面的定義可知:
Tween Animation 的主要作用是在可視物件上執行一系列的變化操作。
舉例來說,就是 Tween Animation 可以改變介面上顯示控制元件的狀態,如 Button 的顯示、隱藏,ImageView 的尺寸縮放等等。
3. Tween Animation 都包括哪幾類動畫,各類動畫的主要作用是什麼?
3.1 Tween Animation 分類
Tween Animation 包括五類動畫,分別是:
- AlphaAnimation
- ScaleAnimation
- TranslateAnimation
- RotateAnimation
- AnimationSet
3.2 各類動畫主要作用
- AlphaAnimation
主要用於控制 View 的可見性(顯示|隱藏)。
- ScaleAnimation
主要用於縮放 View 大小。
- TranslateAnimation
主要用於移動 View 的位置。
- RotateAnimation
主要用於旋轉 View。
- AnimationSet
某些場景僅靠上面單一型別的動畫是無法實現的,需要多個型別的動畫組合才能達到最終的效果,此時 AnimationSet 就派上用場了,AnimationSet 的主要作用就是組合各類 Tween Animation。
4. 如何使用 Tween Animation?
建立 Tween Animation 的方式共兩種:
- XML
- CODE
4.1 通過 XML 建立 Tween Animation
4.1.1 通過 XML 建立 AlphaAnimation
4.1.1.1. 語法
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="integer"
android:fillAfter="true|false"
android:fillBefore="true|false"
android:fillEnabled="true|false"
android:interpolator="@[package:]anim/interpolator_resource"
android:repeatCount="infinite|integer"
android:repeatMode="reverse|restart"
android:fromAlpha="float"
android:toAlpha="float" />
複製程式碼
4.1.1.2. 屬性詳解
屬性 | 含義 | 取值範圍 |
---|---|---|
xmlns:android | 宣告 XML 佈局檔案屬性名稱空間 | http://schemas.android.com/apk/res/android |
android:duration | 動畫的執行時間 | 必須大於等於 0,否則程式將報錯 |
android:fillAfter | 動畫執行完之後是否保留動畫結束時的狀態 | true 儲存,false 不儲存(預設 false) |
android:fillBefore | 動畫開始執行之前,是否應用動畫的起始狀態 | true 應用,false 不應用(預設 true) |
android:fillEnabled | 該屬性決定了 fillBefore 屬效能否生效 | true fillBefore 生效,false fillBefore 不生效(預設) |
android:interpolator | 插值器,決定了動畫的變化率 | Android,Custom |
android:repeatCount | 動畫重複的次數 | 整型數字,預設為 0。當為負數時,表示無限迴圈 |
android:repeatMode | 當動畫的執行次數大於 1 時,下一次動畫執行的方式 | 重新開始(預設),反著執行 |
android:fromAlpha | 動畫開始時的透明度 | 0 透明,1 不透明 |
android:toAlpha | 動畫結束時的透明度 | 0 透明,1 不透明 |
4.1.1.3. 示例
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/integer_one_thousand_and_two_hundred"
android:fillAfter="true"
android:fromAlpha="@integer/integer_one"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:toAlpha="@integer/integer_zero" />
複製程式碼
最終效果如下:
4.1.1.4. 部分屬性解釋
4.1.1.4.1. android:fillAfter
動畫執行完之後,是否保留最終的狀態,true 保留,false,不保留。
1.android:fillAfter="false"
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/integer_one_thousand_and_two_hundred"
android:fillAfter="false"
android:fromAlpha="@fraction/scale_normal"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toAlpha="@integer/integer_zero" />
複製程式碼
android:fillAfter="true"
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/integer_one_thousand_and_two_hundred"
android:fillAfter="true"
android:fromAlpha="@fraction/scale_normal"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toAlpha="@integer/integer_zero" />
複製程式碼
4.1.1.4.2. android:fillBefore
第二次動畫開始執行時,是否從動畫開始的狀態(fromAlpha)開始執行,true 是,false 不是。
本來想解釋下這個屬性和 android:fillEnabled 的,但由於 AlphaAnimation 應用此屬性時,效果不明顯,所以作罷。
4.1.2 通過 XML 建立 ScaleAnimation
4.1.2.1. 語法
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="integer"
android:fillAfter="true|false"
android:fillBefore="true|false"
android:fillEnabled="true|false"
android:interpolator="@[package:]anim/interpolator_resource"
android:repeatCount="infinite|integer"
android:repeatMode="reverse|restart"
android:fromXScale="float"
android:fromYScale="float"
android:toXScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float"
/>
複製程式碼
4.1.2.2. 屬性詳解
屬性 | 含義 | 取值範圍 |
---|---|---|
xmlns:android | 宣告 XML 佈局檔案屬性名稱空間 | http://schemas.android.com/apk/res/android |
android:duration | 動畫的執行時間 | 必須大於等於 0,否則程式將報錯 |
android:fillAfter | 動畫執行完之後是否保留動畫結束時的狀態 | true 儲存,false 不儲存(預設 false) |
android:fillBefore | 動畫開始執行之前,是否應用動畫的起始狀態 | true 應用,false 不應用(預設 true) |
android:fillEnabled | 該屬性決定了 fillBefore 屬效能否生效 | true fillBefore 生效,false fillBefore 不生效(預設) |
android:interpolator | 插值器,決定了動畫的變化率 | Android,Custom |
android:repeatCount | 動畫重複的次數 | 整型數字,預設為 0。當為負數時,表示無限迴圈 |
android:repeatMode | 當動畫的執行次數大於 1 時,下一次動畫執行的方式 | 重新開始(預設),反著執行 |
android:fromXScale | 動畫開始時的 X 軸方向上的縮放比例 | 浮點數,預設值為 1(大小保持不變) |
android:fromYScale | 動畫開始時的 Y 軸方向上的縮放比例 | 浮點數,預設值為 1(大小保持不變) |
android:toXScale | 動畫結束時的 X 軸方向上的縮放比例 | 浮點數,預設值為 1(大小保持不變) |
android:toYScale | 動畫結束時的 Y 軸方向上的縮放比例 | 浮點數,預設值為 1(大小保持不變) |
android:pivotX | 動畫執行時 X 軸方向上不變的座標點(軸心) | 浮點數,預設值為縮放物件的左邊 |
android:pivotY | 動畫執行時 Y 軸方向上不變的座標點(軸心) | 浮點數,預設值為縮放物件的上邊 |
4.1.2.3. 示例
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/integer_one_thousand_and_two_hundred"
android:fillAfter="true"
android:fromXScale="@fraction/percent_one_hundred"
android:fromYScale="@fraction/percent_one_hundred"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="@fraction/percent_fifty"
android:pivotY="@fraction/percent_fifty"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:toXScale="@fraction/percent_two_hundred"
android:toYScale="@fraction/percent_two_hundred" />
複製程式碼
最終效果如下:
4.1.2.4. 部分屬性解釋
4.1.2.4.1. android:fillAfter
動畫執行完之後,是否保留最後的狀態,true 保留,false,不保留。
1.android:fillAfter="false"
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="false"
android:fromXScale="1"
android:fromYScale="1"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toXScale="2"
android:toYScale="2" />
複製程式碼
2.android:fillAfter="true"
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fromXScale="1"
android:fromYScale="1"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toXScale="2"
android:toYScale="2" />
複製程式碼
4.1.2.4.2. android:fillBefore
第二次動畫開始執行時,是否從動畫開始的狀態(fromXScale,fromYScale)開始執行,true 是,false 不是。
按照開發文件的說法,fillEnabled 屬性將對 fillBefore 屬性有一定的影響,但我在執行的時候,發現實際上並沒有什麼影響,即 fillBefore 屬性最終有沒有起作用,跟 fillEnabled 是不是 true 沒有關係(即使當 fillEnabled = false 時,fillBefore = true 還是起作用)。
android:fillAfter="false"
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:fillAfter="true"
android:fillBefore="false"
android:fromXScale="2"
android:fromYScale="2"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toXScale="4"
android:toYScale="4" />
複製程式碼
當第一次動畫執行完畢之後,再此執行動畫的時候,動畫執行的目標物件會從原始狀態(閃一下)跳轉至 from*Scale,然後從 from*Scale 到 to*Scale。
奈何錄製的 GIF 中剛好丟了這一幀,小老弟,你就用心去體會吧。
android:fillAfter="true"
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:fillAfter="true"
android:fillBefore="true"
android:fromXScale="2"
android:fromYScale="2"
android:interpolator="@android:anim/linear_interpolator"
android:toXScale="4"
android:toYScale="4" />
複製程式碼
當第一次動畫執行完畢之後,再此執行動畫的時候,動畫執行的目標物件會直接從 from*Scale 到 to*Scale。
4.1.2.4.3. android:pivotX,android:pivotY
動畫執行目標物件執行縮放動畫時,保持不變的座標點,預設為目標物件的左上角(動畫執行目標物件左邊與上邊的焦點)。
當 pivotX,pivotY 不為 0 時,最終的 pivotX 和 pivotY 為:
pivotX = left(動畫執行目標物件左邊絕對座標) + pivotX
pivotY = top(動畫執行目標物件上邊絕對座標) + pivotY
即最終的軸心點的座標都是相對動畫執行目標物件左邊和上邊而言的。
- 預設值
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="true"
android:fromXScale="1"
android:fromYScale="1"
android:interpolator="@android:anim/linear_interpolator"
android:toXScale="2"
android:toYScale="2" />
複製程式碼
android:pivotX="0",android:pivotY="0"
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="true"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="0"
android:pivotY="0"
android:interpolator="@android:anim/linear_interpolator"
android:toXScale="2"
android:toYScale="2" />
複製程式碼
由於 android:pivotX="0" 和 android:pivotY="0" 均為 0,所以放大動畫的軸心點還在動畫執行目標物件的左上角。
android:pivotX="50%",android:pivotY="50%"
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="true"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/linear_interpolator"
android:toXScale="2"
android:toYScale="2" />
複製程式碼
pivotX、pivotY 分別為動畫執行目標物件寬、高的一半,所以,放大動畫的軸心點是動畫執行目標物件的中心。
android:pivotX="50%p",android:pivotY="50%p"
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="true"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%p"
android:pivotY="50%p"
android:interpolator="@android:anim/linear_interpolator"
android:toXScale="0.1"
android:toYScale="0.1" />
複製程式碼
pivotX、pivotY 分別為動畫執行目標物件父容器寬、高的一半,所以,放大動畫的軸心點是:
pivotX = left + parent width/2
pivotY = top + parent height/2
4.1.3 通過 XML 建立 TranslateAnimation
4.1.3.1. 語法
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="integer"
android:fillAfter="true|false"
android:fillBefore="true|false"
android:fillEnabled="true|false"
android:interpolator="@[package:]anim/interpolator_resource"
android:repeatCount="infinite|integer"
android:repeatMode="reverse|restart"
android:fromXDelta="float"
android:fromYDelta="float"
android:toXDelta="float"
android:toYDelta="float"
/>
複製程式碼
4.1.3.2. 屬性詳解
屬性 | 含義 | 取值範圍 |
---|---|---|
xmlns:android | 宣告 XML 佈局檔案屬性名稱空間 | http://schemas.android.com/apk/res/android |
android:duration | 動畫的執行時間 | 必須大於等於 0,否則程式將報錯 |
android:fillAfter | 動畫執行完之後是否保留動畫結束時的狀態 | true 儲存,false 不儲存(預設 false) |
android:fillBefore | 動畫開始執行之前,是否應用動畫的起始狀態 | true 應用,false 不應用(預設 true) |
android:fillEnabled | 該屬性決定了 fillBefore 屬效能否生效 | true fillBefore 生效,false fillBefore 不生效(預設) |
android:interpolator | 插值器,決定了動畫的變化率 | Android,Custom |
android:repeatCount | 動畫重複的次數 | 整型數字,預設為 0。當為負數時,表示無限迴圈 |
android:repeatMode | 當動畫的執行次數大於 1 時,下一次動畫執行的方式 | 重新開始(預設),反著執行 |
android:fromXDelta | 動畫開始時的 X 軸方向上的起始座標 | 浮點數或者百分數。 當為浮點數時,表示相對於左邊的距離; 當為百分數時(百分數後不帶 p,如 5%),表示相對於動畫執行目標物件寬度的百分之多少; 當為百分數時(百分數後帶 p,如 5%p),表示相對於動畫執行目標物件所在父容器寬度的百分之多少; 預設值為 0。 |
android:fromYDelta | 動畫開始時的 Y 軸方向上的起始座標 | 浮點數或者百分數。 當為浮點數時,表示相對於上邊的距離; 當為百分數時(百分數後不帶 p,如 5%),表示相對於動畫執行目標物件高度的百分之多少; 當為百分數時(百分數後帶 p,如 5%p),表示相對於動畫執行目標物件所在父容器高度的百分之多少; 預設值為 0。 |
android:toXDelta | 動畫結束時的 X 軸方向上的結束座標 | 浮點數或者百分數。 當為浮點數時,表示相對於左邊的距離; 當為百分數時(百分數後不帶 p,如 5%),表示相對於動畫執行目標物件寬度的百分之多少; 當為百分數時(百分數後帶 p,如 5%p),表示相對於動畫執行目標物件所在父容器寬度的百分之多少; 預設值為 0。 |
android:toYDelta | 動畫結束時的 Y 軸方向上的結束座標 | 浮點數或者百分數。 當為浮點數時,表示相對於上邊的距離; 當為百分數時(百分數後不帶 p,如 5%),表示相對於動畫執行目標物件高度的百分之多少; 當為百分數時(百分數後帶 p,如 5%p),表示相對於動畫執行目標物件所在父容器高度的百分之多少; 預設值為 0。 |
4.1.3.3. 示例
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@anim/overshoot_interpolator"
android:toXDelta="0"
android:toYDelta="50%p" />
複製程式碼
最終效果如下:
4.1.4 通過 XML 建立 RotateAnimation
4.1.4.1. 語法
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="integer"
android:fillAfter="true|false"
android:fillBefore="true|false"
android:fillEnabled="true|false"
android:interpolator="@[package:]anim/interpolator_resource"
android:repeatCount="infinite|integer"
android:repeatMode="reverse|restart"
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float"
/>
複製程式碼
4.1.4.2. 屬性詳解
屬性 | 含義 | 取值範圍 |
---|---|---|
xmlns:android | 宣告 XML 佈局檔案屬性名稱空間 | http://schemas.android.com/apk/res/android |
android:duration | 動畫的執行時間 | 必須大於等於 0,否則程式將報錯 |
android:fillAfter | 動畫執行完之後是否保留動畫結束時的狀態 | true 儲存,false 不儲存(預設 false) |
android:fillBefore | 動畫開始執行之前,是否應用動畫的起始狀態 | true 應用,false 不應用(預設 true) |
android:fillEnabled | 該屬性決定了 fillBefore 屬效能否生效 | true fillBefore 生效,false fillBefore 不生效(預設) |
android:interpolator | 插值器,決定了動畫的變化率 | Android,Custom |
android:repeatCount | 動畫重複的次數 | 整型數字,預設為 0。當為負數時,表示無限迴圈 |
android:repeatMode | 當動畫的執行次數大於 1 時,下一次動畫執行的方式 | 重新開始(預設),反著執行 |
android:fromDegrees | 動畫開始時的角度 | 浮點數,預設值為 0 |
android:toDegrees | 動畫結束時的角度 | 浮點數,預設值為 0 |
android:pivotX | 動畫執行時 X 軸方向上旋轉中心(軸心) | 浮點數,預設值為旋轉物件的左邊 |
android:pivotY | 動畫執行時 Y 軸方向上旋轉中心(軸心) | 浮點數,預設值為旋轉物件的上邊 |
4.1.4.2. 示例
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toDegrees="360" />
複製程式碼
最終效果如下:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="0"
android:pivotY="0"
android:toDegrees="360" />
複製程式碼
最終效果如下:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" />
複製程式碼
最終效果如下:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50%p"
android:pivotY="50%p"
android:toDegrees="360" />
複製程式碼
最終效果如下:
由上面幾個示例不難看出,此處的 pivot* 和 ScaleAnimation 動畫中概念完全一樣,所以,只要之前理解了這個概念,在這裡也沒有什麼困難,直接用就好了。
4.1.5 通過 XML 建立 AnimationSet
4.1.5.1. 語法
<?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>
複製程式碼
4.1.5.2. 屬性詳解
屬性 | 含義 | 取值範圍 |
---|---|---|
xmlns:android | 宣告 XML 佈局檔案屬性名稱空間 | http://schemas.android.com/apk/res/android |
android:interpolator | 插值器,決定了動畫的變化率 | Android,Custom |
android:shareInterpolator | 多個子動畫是否共用插值器 | true 共用,false 不共用(預設) |
4.1.5.3. 示例
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/integer_three_thousand"
android:fillAfter="true"
android:shareInterpolator="true">
<translate
android:fromXDelta="@integer/integer_zero"
android:fromYDelta="@integer/integer_zero"
android:toXDelta="@integer/integer_zero"
android:toYDelta="@integer/integer_two_hundred" />
<alpha
android:fromAlpha="@integer/integer_one"
android:toAlpha="@fraction/scale_smaller" />
<rotate
android:fromDegrees="@integer/integer_zero"
android:pivotX="@fraction/percent_fifty"
android:pivotY="@fraction/percent_fifty"
android:toDegrees="@integer/integer_seven_hundred_and_five" />
</set>
複製程式碼
最終效果如下:
4.2 通過 CODE 建立 Tween Animation
在 Android 中,大多數情況下,能通過 XML 實現的功能幾乎也能通過程式碼實現,接下來,讓我們看下如何通過程式碼實現上面的動畫。
4.2.1 通過 CODE 建立 AlphaAnimation
4.2.1.1. 語法
AlphaAnimation alphaAnimation = new AlphaAnimation(float fromAlpha, float toAlpha);
alphaAnimation.setInterpolator(Interpolator i);
alphaAnimation.setDuration(long durationMillis);
AnimationTarget.startAnimation(alphaAnimation);
複製程式碼
4.2.1.2. 示例
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.1f);
alphaAnimation.setInterpolator(new AccelerateInterpolator());
alphaAnimation.setFillAfter(mIsSaveAnimationState);
alphaAnimation.setDuration(800);
mTarget.startAnimation(alphaAnimation);
複製程式碼
最終效果如下:
4.2.2 通過 CODE 建立 ScaleAnimation
4.2.2.1. 語法
ScaleAnimation scaleAnimation = new ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue);
scaleAnimation.setInterpolator(Interpolator i);
scaleAnimation.setDuration(long durationMillis);
AnimationTarget.startAnimation(scaleAnimation);
複製程式碼
4.2.2.2. 示例
ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 2f, 1f, 2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setInterpolator(new AccelerateInterpolator());
scaleAnimation.setFillAfter(mIsSaveAnimationState);
scaleAnimation.setDuration(800);
mTarget.startAnimation(scaleAnimation);
複製程式碼
最終效果如下:
4.2.3 通過 CODE 建立 TranslateAnimation
4.2.3.1. 語法
TranslateAnimation translateAnimation = new TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta);
translateAnimation.setInterpolator(Interpolator i);
translateAnimation.setDuration(long durationMillis);
AnimationTarget.startAnimation(translateAnimation);
複製程式碼
4.2.3.2. 示例
TranslateAnimation translateAnimation = new TranslateAnimation(0f, 200f, 0f, 200f);
translateAnimation.setInterpolator(new AccelerateInterpolator());
translateAnimation.setFillAfter(mIsSaveAnimationState);
translateAnimation.setDuration(800);
mTarget.startAnimation(translateAnimation);
複製程式碼
最終效果如下:
4.2.4 通過 CODE 建立 RotateAnimation
4.2.4.1. 語法
RotateAnimation rotateAnimation = new RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue);
rotateAnimation.setInterpolator(Interpolator i);
rotateAnimation.setDuration(long durationMillis);
AnimationTarget.startAnimation(rotateAnimation);
複製程式碼
4.2.4.2. 示例
RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setInterpolator(new AccelerateInterpolator());
rotateAnimation.setFillAfter(mIsSaveAnimationState);
rotateAnimation.setDuration(800);
mTarget.startAnimation(rotateAnimation);
複製程式碼
最終效果如下:
4.2.5 通過 CODE 建立 AnimationSet
4.2.5.1. 語法
AnimationSet animationSet = new AnimationSet(boolean shareInterpolator);
animationSet.addAnimation(Animation a)
...
AnimationTarget.startAnimation(animationSet);
複製程式碼
4.2.5.2. 示例
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.5f);
alphaAnimation.setInterpolator(new AccelerateInterpolator());
alphaAnimation.setFillAfter(mIsSaveAnimationState);
alphaAnimation.setDuration(800);
ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 2f, 1f, 2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setInterpolator(new AccelerateInterpolator());
scaleAnimation.setFillAfter(mIsSaveAnimationState);
scaleAnimation.setDuration(800);
RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setInterpolator(new AccelerateInterpolator());
rotateAnimation.setFillAfter(mIsSaveAnimationState);
rotateAnimation.setDuration(800);
AnimationSet animationSet = new AnimationSet(false);
animationSet.setFillAfter(true);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(rotateAnimation);
mTarget.startAnimation(animationSet);
複製程式碼
最終效果如下:
5. 自定義插值器
5.1 什麼是插值器,插值器的作用是什麼?
插值器是動畫執行速率調節器,主要用來控制動畫的變化率。
5.2 常用的插值器有哪些?
5.2.1 常用插值器彙總
類名 | 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 | 加速 超出,返回終點 |
5.2.2 插值器示例
5.2.2.1 AccelerateDecelerateInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.2.2.2 AccelerateInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/anticipate_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.2.2.3 AnticipateInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/anticipate_overshoot_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.2.2.4 AnticipateOvershootInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/anticipate_overshoot_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.2.2.5 BounceInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/bounce_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.2.2.6 CycleInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/cycle_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.2.2.7 DecelerateInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/decelerate_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.2.2.8 LinearInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/linear_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.2.2.9 OvershootInterpolator
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/overshoot_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
5.3 自定義插值器的方式有哪些?
自定義插值器的方式有兩種:
- XML
- CODE
5.4 如何自定義插值器
5.4.1. 通過 XML 自定義插值器
通過 XML 自定義插值器的時候,限制性比較大,因為系統只提供了部分插值器的自定義,如 AccelerateInterpolator,有些插值器是不支援自定義的,如 AccelerateDecelerateInterpolator。
接下來,我們就學習下如何自定義 AccelerateInterpolator。
AccelerateInterpolator 中可以自定義的屬性只有:android:factor
android:factor 加速的比率(The acceleration rate),預設值為 1。
複製程式碼
- 預設值
<!-- accelerateInterpolator -->
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<accelerateInterpolator />
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
- 自定義
<!-- custom accelerateInterpolator -->
<?xml version="1.0" encoding="utf-8"?>
<accelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="4.0" />
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/custom_accelerate_interpolator"
android:toXDelta="40%p"
android:toYDelta="0" />
複製程式碼
最終效果如下:
可以通過 XML 自定義插值器,除了 AccelerateInterpolator,還有很多,以下是具體列表:
序號 | 類名 |
---|---|
1 | AccelerateInterpolator |
2 | AnticipateInterpolator |
3 | AnticipateOvershootInterpolator |
4 | CycleInterpolator |
5 | DecelerateInterpolator |
6 | OvershootInterpolator |
5.4.2. 通過 CODE 自定義插值器
相對於通過 XML 自定義插值器而言,通過 CODE 自定義插值器就沒有那麼多限制,可以說唯一能限制你的是你的想象力。
通過程式碼自定義插值器其實也很簡單,只要實現 Interpolator 介面,並實現其中的方法(getInterpolation)就好了。接下來,我們先看下 Google 官方是如何實現插值器的。
//AccelerateDecelerateInterpolator
package android.view.animation;
import android.content.Context;
import android.util.AttributeSet;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the rate of change starts and ends slowly but
* accelerates through the middle.
*/
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
public AccelerateDecelerateInterpolator() {
}
@SuppressWarnings({"UnusedDeclaration"})
public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
}
}
複製程式碼
上面是 AccelerateDecelerateInterpolator 的具體實現,通過程式碼可知,AccelerateDecelerateInterpolator 是通過餘弦函式實現的:
上圖中用藍色框圈出的部分即為 AccelerateDecelerateInterpolator 具體演算法實現。
明白了上面的道理之後,我們就可以自定義插值器。既然 Google 提供了 AccelerateDecelerateInterpolator,那我們就來實現一個 DecelerateAccelerateInterpolator。
由 AccelerateDecelerateInterpolator 應用的函式曲線圖可以發現,在 AccelerateDecelerateInterpolator 中,加速的過程是函式曲線斜率逐漸增大的過程,減速的過程是函式曲線斜率逐漸減小的過程。明白這個之後,如何自定義 DecelerateAccelerateInterpolator 就更明確了:
找一個開始時斜率逐漸減小,當過了某個臨界點之後,斜率又逐漸增加的曲線。
大概就是下面這個樣子:
趕緊回憶下,在我們初、高中學習的過程中有沒有哪個函式的曲線跟上面的這個相似的?當然有,三次函式和正切函式。接下來,我們用正切函式實現。
上圖中用藍色框圈出的部分即是 DecelerateAccelerateInterpolator 實現的理論基礎,接下來,只需要在對這個函式稍作修改即可:
- Interpolator 介面中 getInterpolation 方法中 input 的取值範圍為 [0,1],而藍色框圈出的 X 的取值範圍為 [-π/4,π/4],所以,需要將 [0,1] 轉換為 [-π/4,π/4]:
π/2 * input - π/4
- 正切函式在 [-π/4,π/4] 取值範圍內,相應的函式值的取值範圍為[-1,1],而 getInterpolation 最終返回值的取值範圍為 [0,1],所以,需要將 [-1,1] 轉換為 [0,1]:
(tan(π/2 * input - π/4) + 1)/2
因此最終的實現為:
public class DecelerateAccelerateInterpolator implements Interpolator {
@Override
public float getInterpolation(float input) {
return (float) ((Math.tan(Math.PI/2 * input - Math.PI/4) + 1)/2);
}
}
複製程式碼
TranslateAnimation translateAnimation = new TranslateAnimation(0f, 0f, 0f, 800f);
translateAnimation.setInterpolator(new DecelerateAccelerateInterpolator());
translateAnimation.setFillAfter(mIsSaveAnimationState);
translateAnimation.setDuration(1800);
mTarget.startAnimation(translateAnimation);
複製程式碼
最終效果如下:
6. 應用例項
Tween Animation 應用場景還是很多的,如控制介面中元素的顯示、隱藏:
我在這裡只是拋磚引玉而已,具體如何使用,還要靠大家發揮自己的想象力。