前言
Android
動畫也是
Android
系統中一個很重要的子產品, 在平時開發中, 為了做出炫酷的效果, 動畫可以說是必不可少的; 本文将總結
Android
中與動畫相關的部分, 文中部分内容整理自文末參考連結, 權作筆記~
需要聲明的是文章不會詳細通過源碼去講解各種動畫的實作細節, 因為相對來說, 動畫的熟練使用更為重要, 是以本文隻是提一下關鍵的動畫源碼部分
正文
一. 概述
Android
中動畫分為三大類:
View
動畫,
Transition
(過渡動畫), 屬性動畫; 下文也将從這三個方面進行總結和講解
動畫的本質實際上就是将作用對象的屬性值在一段時間内緩慢的改變, 将每一個小的時間片段對應的屬性值改變作用到對象并進行不斷重繪, 造成肉眼看起來的的動畫效果~
二. View動畫
2.1 基本使用總結
View
動畫分為四種, 如下表:
名稱 | 标簽 | 子類 | 效果 |
---|---|---|---|
平移動畫 | <translate> | TranslateAnimation | 移動 |
縮放動畫 | <scale> | ScaleAnimation | 縮放 |
旋轉動畫 | <rotate> | RotateAnimation | 旋轉 |
透明度 | <alpha> | AlphaAnimation |
注: 動畫中還有一種叫幀動畫, 這裡也歸為
View
動畫中, 後文單獨講解
View
動畫可以使用
xml
描述, 也可以使用代碼描述(即使用上表中的四個子類); 使用
xml
描述的文法格式如下:
注: 位置為
res/anim/filename.xml
<?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]"
android:fillAfter="[true | false]"
android:duration="int"
android:repeatMode="[reverse | restart]">
<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
-
: 表示集合中的動畫是否和集合共享同一個插值器; 如果集合不指定插值器, 那麼子動畫需要單獨指定或者使用預設插值器android:shareInterpolator
-
: 軸點android:pivotX
坐标x
-
android:pivotY
y
-
: 動畫結束之後,android:fillAfter
是否停留在結束位置,View
表示停留在結束位置,true
表示不停留false
在代碼中使用
View
動畫:
Button button = findViewById(R.id.button);
Animatoin animation = AnimationUtils.loadAnimation(this, R.anim.animation_item);
button.startAnimation(animation);
2.2 自定義View動畫
TranslateAnimation
,
ScaleAnimation
RotateAnimation
, 和
AlphaAnimation
都繼承自
Animation
; 如果要自定義
View
動畫的話, 也需要繼承
Animation
, 并重寫
Animation.initialize()
和
Animation.applyTransformation()
方法;
initialize()
顧名思義就是進行一些初始化工作, 比如設定屬性的初始值等,
applyTransformation()
就是根據時間的流失量來計算出目前時間片段所對應的屬性值, 并設定到對應的作用對象(對于
View
動畫來說該對象就是
View
); 這裡的設定往往是通過
Matrix
來作用的, 如下以
TranslateAnimation.applyTransformation()
為例
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float dx = mFromXDelta;
float dy = mFromYDelta;
if (mFromXDelta != mToXDelta) {
dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime); // 通過時間流失量計算出x的改變量
}
if (mFromYDelta != mToYDelta) {
dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime); // 通過時間流失量計算出y的改變量
}
t.getMatrix().setTranslate(dx, dy); // 通過Matrix作用到對象
}
上述代碼其實也可以當做自定義
View
動畫的模闆代碼, 自定義
View
動畫時, 可以使用
Camera
來配合計算改變量; 關于
Camera
Matrix
的使用, 可以參見
部落格2.3 幀動畫
幀動畫就是順序播放一組預先定義好的圖檔, 系統提供了
AnimationDrawable
來使用幀動畫
xml
定義如下:
/res/drawable/filename.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/item" android:duration="100"/>
<item android:drawable="@drawable/item" android:duration="100"/>
<item android:drawable="@drawable/item" android:duration="100"/>
<item android:drawable="@drawable/item" android:duration="100"/>
</animation-list>
使用幀動畫時, 當圖檔較多或者較大時可能引起
OOM
三. Transition(過渡動畫)
過渡動畫其實是用于控制
ViewGroup
的
Item
的出場效果, 或者
Activity
之間的切換效果等
3.1 LayoutAnimation
xml
實作格式如下:
/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="[normal | reverse | random]"
android:animation="@anim/anim_item"/>
-
: 子元素延遲多少時間執行動畫; 比如子元素入場動畫時間周期為android:delay
, 那麼300ms
表示每個每個子元素都需要延遲0.5
才能播放入場動畫, 總體來說, 第一個子元素延遲150ms
開始播放動畫, 第二個子元素延遲150ms
開始播放動畫, 以此類推300ms
-
:android:animationOrder
表示順序顯示, 即排在前面的子元素先開始動畫;normal
表示逆向顯示;reverse
表示随機顯示random
當定義好
layoutAnimation
之後, 在布局檔案中就可以通過
ViewGroup
的屬性
android:layoutAnimation="@anim/anim_layout"
來指定入場動畫了~
代碼實作, 格式如下: 即通過
LayoutAnimationController
實作
ListView listView = findViewById(R.id.list);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);
3.2 Activity的切換效果
- 當啟動一個
的時候, 可以按照如下方式為其添加自定義的切換效果:Activity
Intent intent = new Intent(this, AnimActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim);
- 當
退出時, 可以如下添加切換效果:Activity
@Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim);
}
可以看出, 都是使用
overridePendingTransition()
來指定切換動畫, 同時需要注意的是這個方法必須在
startActivity(intent)
或者
finish()
之後被調用才能生效
- 為
添加切換動畫: 可以通過Fragment
來添加切換動畫; 需要注意的是該動畫必須是FragmentTransaction.setCustomAnimations()
動畫, 不能用屬性動畫(因為屬性動畫在View
引入,API 11
也是Fragment
才引入的)API 11
四. 屬性動畫
屬性動畫是在
Android 3.0
(
API 11
)開始引入的; 屬性動畫可以用
xml
實作, 也可以用代碼實作, 但是一般都是用代碼實作
4.1 基本使用
4.1.1 ViewPropertyAnimator
操作
View
屬性值, 可以通過
View.animate()
來擷取一個
ViewPropertyAnimator
對象, 然後就可以通過
ViewPropertyAnimator
來操作該對象的屬性值了~ 可以操作的屬性值參見下圖(圖檔來源, 參見文末參考連結):
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLCJUJ0kTJ3UUJ4EUJBhTJ1UUJ3EUJwgTJ2UUJFlTJxIUJ1UUJy9Gdh1WauFUe0JXZw9mcQdXZpZ1Lc52bpRXYtlmbB9CX0N3bw9CXn1Wavw1bp5iY1hGdpdmLwlnclR3c1h2Lc9CX6MHc0RHaiojIsJye.png)
使用示例如
View.animate().setDuration(500).alpha(0.5);
4.1.2 ObjectAnimator
也是針對
View
的特定屬性, 同時還要求該屬性提供了對應的
set
get
方法, 基本使用如下; 因為
ObjectAnimator
是通過屬性的
set
方法來不斷改變屬性值的, 是以
set
方法是一定需要的, 至于
get
方法隻是用于擷取動畫開始的初始值的, 如果明确指定了初始值的話, 也可以提供
get
方法(如果沒有提供
get
方法, 同時又沒有指定初始值的話, 将
Crash
; 如果沒有
set
方法, 不會
Crash
, 隻是沒有效果而已)
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0, 65);
animator.start();
如果一個屬性沒有
set
方法的話, 解決方法有以下三種:
- 如果有權限的話, 自己給對象加上
set
方法get
- 用一個類來包裝原始對象, 間接為其提供
set
get
- 采用
, 監聽動畫過程, 自己實作屬性改變ValueAnimator
4.2 插值器
所謂插值器就是屬性改變的速度, 系統提供了如下插值器:
AccelerateDecelerateInterpolator | LinearInterpolator | AccelerateInterpolator |
DecelerateInterpolator | AnticipateInterpolator | OvershootInterpolator |
AnticipateOvershootInterpolator | BounceInterpolator | CycleInterpolator |
PathInterpolator | ||
| | |
其中
FastOutLinearInInterpolator
FastOutSlowInInterpolator
LinearOutSlowInInterpolator
是
Android 5.0(API 21)
引入的三個新的
Interpolator
模型, 并把它們加入了
support v4
包中
關于各種插值器的講解, 可以參見
, 該部落格講的比較詳細, 此處不再贅述~
4.3 估值器
估值器即
TypeEvaluator
, 作用是根據目前屬性改變的百分比來計算改變後的屬性值, 用于協助插值器實作非線性運動; 系統提供了如下估值器:
IntEvaluator | IntArrayEvaluator | FloatEvaluator |
FloatArrayEvaluator | ArgbEvaluator | PointFEvaluator |
RectEvaluator |
如果要對其他類型做動畫(非
int
float
Color
), 那麼需要自定義類型估值算法, 即繼承
TypeEvaluator
自己實作其
evaluate()
方法即可
估值器基本使用如下:
ObjectAnimator anim = ObjectAnimator.ofObject(view, "alpha", new FloatEvaluator(), 0, 1);
4.4 監聽器
ViewPropertyAnimator
ObjectAnimator
設定監聽器的方法如下表:
ViewPropertyAnimator | setListener() | setUpdateListener() | withStartAction() | withEndAction() |
ObjectAnimator | addListener() | addUpdateListener() | addPauseListener() |
注:
-
可以通過ViewPropertyAnimator
setListener()
來設定監聽器, 移除監聽器可以通過setUpdateListener()
setListener(null)
來移除;setUpdateListener(null)
獨有的ViewPropertyAnimator
withStartAction()
方法, 可以設定一次性(動畫結束後就自動棄掉了, 即一次有效)的動畫開始或結束的監聽withEndAction()
-
則是用ObjectAnimator
addListener()
來添加一個或多個監聽器, 移除監聽器則是通過addUpdateListener()
removeListener()
來指定移除對象;removeUpdateListener()
支援使用ObjectAnimator
方法暫停, 是以它還多了一個pause()
addPauseListener()
的支援removePauseListener()
-
ViewPropertyAnimator.withStartAction/EndAction()
的獨有方法, 它們和ViewPropertyAnimator
中回調的set/addListener()
onAnimationStart()
相比起來的不同主要有兩點:onAnimationEnd()
withStartAction()
是一次性的, 在動畫執行結束後就自動棄掉了, 就算之後再重用
withEndAction()
來做别的動畫, 用它們設定的回調也不會再被調用; 而
ViewPropertyAnimator
所設定的
set/addListener()
是持續有效的, 當動畫重複執行時, 回調總會被調用
AnimatorListener
設定的回調隻有在動畫正常結束時才會被調用, 而在動畫被取消時不會被執行; 這點和
withEndAction()
的行為是不一緻的
AnimatorListener.onAnimationEnd()
監聽器方法有:
AnimatorListener | onAnimationStart() | onAnimationEnd() | onAnimationCancel() | onAnimationRepeat() |
注: 即使動畫通過
cancle()
方法取消,
onAnimationEnd()
也會被調用; 是以當動畫被取消時, 如果設定了
AnimatorListener
, 那麼
onAnimationCancel()
onAnimationEnd()
都會被調用;
onAnimationCancel()
會先于
onAnimationEnd()
被調用; 由于
ViewPropertyAnimator
不支援重複, 是以這個方法對
ViewPropertyAnimator
相當于無效
五. 動畫注意事項
- 避免使用幀動畫, 易造成
OOM
- 動畫需要考慮暫停和取消; 屬性動畫中有一類無線循環的動畫, 這類動畫在
退出時要及時停止, 否則将導緻Activity
無法釋放進而造成記憶體洩露; 通過驗證後發現Activity
動畫無此問題View
- 使用
動畫之後可能會出現View
無法隐藏的現象, 即View
失效了, 此時可以使用setVisibility(View.GONE)
來清除view.clearAnimation()
動畫即可View
-
以前系統, 不管是Android 3.0
動畫還是屬性動畫, 都隻是作用于View
内容(因為View
以前, 屬性動畫底層其實也是通過Android 3.0
動畫實作的), 新位置無法觸發單擊事件; 從View
開始, 屬性動畫的單擊事件觸發位置為移動後的位置, 但是3.0
動畫仍然在原位置View
END
現在加Android進階開發群;701740775,可免費領取一份最新Android進階架構技術體系大
綱和進階視訊資料,以及這些年年積累整理的所有面試資源筆記。加群請備注csdn領取xx
資料