000 屬性動畫簡介
屬性動畫是 Android API level 11(Android 3.0)中新增的動畫框架,功能強大,擴充套件性強。介紹屬性動畫,就需要說明三個問題:
屬性是什麼?
用官方的話說,Property is a field in an object。更進一步解釋,這裡的屬性是指一個物件中具有 setter/getter 方法的變數。
屬性動畫可以做什麼?
一般來說,動畫是一種視覺效果,但是屬性動畫的內容要更廣泛,除了做一些視覺效果之外,屬性動畫還可以用類似動畫的方式默默改變一些資料。當然,最主要的還是實現視覺效果,包括常見的透明度、縮放、平移、旋轉效果,也可以擴充套件出其他的屬性(比如顏色)。
與之前的 View Animation 有什麼區別?
View Animation 是在 API level 1 開始支援的動畫框架,內容只有基本的透明度、縮放、平移、旋轉,且動畫的物件只能是 View。
二者的區別有以下幾點:
- 屬性動畫實際改變了動畫目標的屬性值,比如平移一個 View,View 的位置真實發生了改變,而 View Animation僅是改變了螢幕繪製位置,真實位置不變。
- 屬性動畫可以作用於沒有繪製到螢幕上的物件。
- 屬性動畫可以作用於非 View 物件,也可以製作四類基本動畫之外的動畫效果。
- View Animation 的程式碼量更少,效率更高。
001 相關API說明
屬性動畫中新新增的類主要是這些:
Animator
作為屬性動畫的基類,Animator 提供了動畫最基本的屬性。
僅列出一部分(我覺得)常用的。
Method Name | Function |
---|---|
start() |
開始播放 |
cancel() |
取消動畫 |
isRunning() |
是否正在播放 |
addListener | 新增監聽回撥 |
setTarget | 設定動畫目標Object |
setDuration | 設定播放時長,單位:毫秒 |
setInterpolator | 設定插值器 |
關於插值器的內容本文暫不介紹了。
ValueAnimator
構造方法
//直接建立
ValueAnimator valueAnimator = new ValueAnimator();
//帶引數建立
ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 2.0f);
// ValueAnimator valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), Color.RED, Color.GREEN);
// ...還有ofArgb,ofInt,ofPropertyValuesHolder
複製程式碼
比起 Animator 增加的一些常用方法
Method Name | Function |
---|---|
setStartDelay | 設定動畫啟動延遲,單位:毫秒 |
addUpdateListener | 新增Value更新的監聽回撥 |
setRepeatMode | 設定重複播放模式,RESTART或REVERSE |
setRepeatCount | 設定重複播放次數 |
ObjectAnimtor
構造方法
//直接建立
ObjectAnimator objectAnimator = new ObjectAnimator();
//帶引數建立
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "alpha", 1.0f, 0.7f);
//...類似的構造方法有很多,就是引數不同,這些引數都可以通過setter方法設定。
複製程式碼
ObjectAnimatior 增加了屬性動畫最基本的方法——設定屬性。
Method Name | Function |
---|---|
setProperty | 設定動畫目標屬性 |
setPropertyName | 通過name設定動畫目標屬性 |
setIntValues(int... values) |
設定一系列動畫引數,按順序執行 |
setFloatValues(float... values) |
設定一系列動畫引數,按順序執行 |
setObjectValues(Object... values) |
設定一系列動畫引數,按順序執行 |
AnimatorSet
AnimatorSet 的功能就是把多個各種 Animator 物件整合成一個動畫,有點類似與 ViewGroup。
Method Name | Function |
---|---|
playTogether | 多個動畫一起播放 |
playSequentially | 多個動畫順序播放 |
010 使用場景分析
Animator物件
ValueAnimator 的功能很單一,比較像“時間軸”,就是設定一個值,在一段時間內以某種規則變化。這也是 ObjectAnimator 實現動畫的基礎。
舉個例子,通過 VlaueAnimator 改變 View 的顏色:
private int mColor = Color.RED;
public ValueAnimator valueAnimator;
//...
//...
valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), mColor, Color.rgb(0,0,255));
valueAnimator.setDuration(3000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mColor = (int) animation.getAnimatedValue();
}
});
複製程式碼
在 onAnimationUpdate
方法中把變化後的顏色重新整理到 UI 介面就行了。效果是這樣的:
相比之下 ObjectAnimator 才是屬性動畫中的主角,建立 ObjectAnimator 物件實現動畫需要有幾個要素:
- propertyName:要變化的屬性名(String)
- target:具有該屬性的 Object 物件
- values:對應屬性的變化值,資料型別要和屬性的型別一致
屬性名接受一個 String 型別的引數,就很容易出錯。可以通過輸入 target 的 object 物件,在程式碼提示中找 setter 方法來確定屬性名。View 的屬性名是比較常用的,比如:
alpha
,rotation
,scaleX
,scaleY
,translationX
,translationY
,rotationX
,rotationY
等。
舉個例子,網路載入中可能會大量用到的一種loading動畫。
ObjectAnimator animator = new ObjectAnimator();
animator.setPropertyName("rotation");
animator.setTarget(ivLoading);
animator.setFloatValues(0,360);
animator.setDuration(900);
animator.setRepeatMode(ObjectAnimator.RESTART);
animator.setRepeatCount(ObjectAnimator.INFINITE);
animator.setInterpolator(new LinearInterpolator());
animator.start();
複製程式碼
程式碼含義比較清晰,需要注意的是setInterpolator
預設的插值器並不是線性的,下面給出兩種效果,左側是 LinearInterpolator ,右側是預設的。
xml實現
xml 實現動畫是一種比較合理的複用動畫方式,可以有效避免在 Controller 層寫過多隻屬於 View 層的程式碼。
屬性動畫的 xml 檔案需要放在res/animator
資料夾下。
語法與 View Animation 差別比較大,大概是這樣子的:
直觀感受就是比 View Animation 的 xml 實現麻煩很多,實際上由於 xml 檔案的限制二者功能上差不多,應該是 View Animation 更加常用一點。(個人感受)
view.animate()
ObjectAnimator 的程式碼寫起來不怎麼好看,因為總是在 objectAnimator.xxx(),比起單獨在Activity中實現某些互動效果,把簡單而常用的動畫效果封裝成工具類會更理想一些。但是互動效果是千變萬化的,總有一些獨特的動畫無法複用。
於是在 API level 12 中,出現了針對 View 的屬性動畫 ViewPropertyAnimtor。ViewProperty 中封裝了 View 相關的常用動畫引數的設定以及多種回撥,並用 ObjectAnimator 實現了動畫效果,對外提供了相當簡單易懂的流式 API,使動畫的程式碼也可以寫的很爽。
使用方法:
- 獲取 ViewPropertyAnimator 物件
ViewPropertyAnimator 沒有 public 的構造方法,只能通過 View 物件的 animate()
方法獲得。使用的 View 物件就是動畫的 target。
ViewPropertyAnimator 物件是會重複使用的,多次呼叫'animate()'只會建立一個 ViewPropertyAnimator。
- 設定動畫引數
相關的 API 名稱都很明確,就不一一介紹效果了
- 設定回撥(可選)
就是setListener
方法。其實所有的動畫都可以設定
Listener ,只是在 ViewPropertyAnimator 中更加重要,因為從 API 可以看出每一種動畫只能傳入一個引數,如果需要同一種動畫多段執行,就只能通過監聽動畫結束脩改引數值再開始動畫。
setListener
方法接收一個 Animator.AnimatorListener 介面的例項,可以直接建立 Animator.AnimatorListener 例項實現所有方法,也可以建立 AnimatorListenerAdapter 只重寫需要的方法。
ViewPropertyAnimator 的複用同樣會影響 Listener,如果是同一個 View 的多個動畫且不相關,需要在不需要 Listener 的動畫中呼叫setListener(null)
。
這裡也應該舉個例子,不過沒什麼好的想法,姑且再寫一遍 loading 動畫,就當對比一下兩種 API 格式吧。(kotlin程式碼,對比一下設定動畫的 API 就好了)
ivLoadingRight.setOnClickListener {
ivLoadingRight.animate()
.rotationBy(360f)
.setDuration(800)
.setInterpolator(LinearInterpolator())
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
ivLoadingRight.animate()
.rotationBy(360f)
.setDuration(800)
.setInterpolator(LinearInterpolator())
.start()
}
}).start()
複製程式碼
011 結語
因為我並沒有做過太多的動畫效果,剛開始寫的時候只想總結一下各種方法的用法和效果,然而那樣就會不能避免的翻譯官方文件,且內容雜亂,不易整理 demo。於是先寫了一些簡單的動畫效果,依據實際程式碼反向整理了這篇文章。
文中 gif 圖對應程式碼都在示例工程(AnimatorSample)中,地址:https://github.com/xhd-Git/Samples