今天的文章里,我將會和大家討論對動畫流的控制。我們可以通過Animator系列的API來控制動畫的開始、停止和取消。在 KitKat也就是API level 19中,我們還可以控制動畫的暫停和恢復。在本文中,我將會帶你體驗整個動畫流的控制,並且通過一些函數方法來讓你能夠觀察到動畫的狀態。
動畫流介紹
在之前的教程中,我們已經使用過多次Animator.start這個方法。這個方法是用來讓動畫從第一幀開始播放。該方法只是動畫流控制方法集中的一個方法而已,完整的方法集合如下所示:
1
2
3
4
5
6
|
; html-script: false ]
Animator.start() // start the animation from the beginning
Animator.end() // end the animation
Animator.cancel() // cancel the animation
Animator.pause() // added in API 19; pause the animation
Animator.resume() // added in API 19; resume a paused animation
|
start這個方法顧名思義是用來讓動畫從開頭開始播放的。如果動畫設置了一個大於0的播放延遲(startDelay),那么調用該方法后還需要等到延遲的時間過去才回開始播放。
我們有兩種停止動畫的方法,你可以用end方法抑或cancel方法來停止一個播放着的動畫。在兩種方式中動畫都會終止並且只有再次調用start方法才會重新開始播放。兩者的區別則在於停止后動畫所在的狀態,當你使用cancel方法來停止動畫后,動畫只是停止了它的時間軸,動畫的狀態會停在一個中間態(intermediate state)。如果通過end 方法來停止一個動畫,那么動畫會直接快進到該動畫最后一幀並且停止,所有的對象都會保持在動畫最終結束后的狀態。
在 Kitkat 中增加的沒有怎么被大家關注到的新API則是帶來了動畫可以暫停和恢復的能力。在那之前,一個動畫如果被取消並且停留在當前的中間態,此時你用start方法去重啟動畫,動畫只會從一開始重新播放。現在,你則可以調用pause方法來暫停當前播放中的動畫,pause也會有和cancel方法一樣的功效讓動畫停留在中間態,但是當你使用resume 方法去恢復這個動畫的時候,動畫會從這個狀態繼續播放下去。
現在,讓我們來實踐下看看效果。我們新建一個 Activity 並且包含一個 私有的動畫對象。並且在 onCreate 回調中初始化這個動畫。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
; html-script: false ]
private ObjectAnimator anim;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.property_animations_flow);
ImageView someImage = (ImageView) findViewById(R.id.some_image);
anim = ObjectAnimator.ofFloat(someImage, "rotation", 0, 360);
anim.setDuration(1000);
anim.setRepeatCount(5);
anim.setRepeatMode(ObjectAnimator.RESTART);
}
|
我們的動畫是一個簡單的旋轉動畫,它將把一個圖片完整旋轉360度五次。被旋轉的圖片會在 layout 的 XML 文件中定義好,並且給予一個叫some_image的id。這個layout同時也包含了五個按鈕分別是:Start、End、Cancel、Pause以及Resume。這五個按鈕分別代表了動畫的五個調用方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
; html-script: false ]
public void startAnimation(View view) {
anim.start();
}
public void endAnimation(View view) {
anim.end();
}
public void cancelAnimation(View view) {
anim.cancel();
}
public void pauseAnimation(View view) {
anim.pause();
}
public void resumeAnimation(View view) {
anim.resume();
}
|
這些方法只是簡單的調用了相應的動畫控制調用。下面會有兩張gif圖片來演示效果。上邊的動畫展示了end方法和cancel方法的區別。可以注意到,cancel讓圖片保持在停止時的中間態,但是end則讓動畫到了最后的狀態。
下邊的動畫則演示了pause和resume方法。可以注意到,pause 和cancel都暫停了動畫的時間軸。但是現在我們可以用resume 調用去恢復動畫的時間軸了。
動畫狀態的查詢
有些時候,我們需要去查詢當前動畫的狀態,這個需求可以通過下面這些方法來完成。
1
2
3
4
|
; html-script: false ]
boolean isStarted() // added in API 14
boolean isRunning()
boolean isPaused() // added in API 19
|
如果當前動畫已經調用了start函數並且還沒播放完成也沒有被取消掉,那么isStarted方法會返回true。請注意,isStarted 方法最低的 API 需求是 14.同時,就算是在動畫播放延遲中,該方法依然會返回 true。這就是這個方法和 isRunning 方法的不同點,isRunning 方法只會在動畫確實在播放並且還沒停止的時候返回 true。
在 API 19 的時候,isPaused 方法被加入進來。這是由於那時候動畫可以被暫停和恢復了,如果 isPaused 返回了 true,那么說明當前動畫是在暫停狀態下,反之亦然。
為了演示這些觀察方法的效果,我們會通過一個包含三個顯示動畫狀態文本框的例子來解釋。這三個文本框都會在Activity中做為TextView成員變量存在。
1
2
3
4
|
; html-script: false ]
private TextView isStartedText;
private TextView isRunningText;
private TextView isPausedText;
|
於此同時,我們在onCreate中添加下列三行代碼來把這些文本框從layout中獲取到。
1
2
3
4
|
; html-script: false ]
isStartedText = (TextView) findViewById(R.id.status_is_started);
isRunningText = (TextView) findViewById(R.id.status_is_running);
isPausedText = (TextView) findViewById(R.id.status_is_paused);
|
我們還創建了一個根據當前動畫狀態來更新這些文本框的方法。
1
2
3
4
5
6
|
; html-script: false ]
public void setStatusTexts() {
isStartedText.setText("isStarted = " + anim.isStarted());
isRunningText.setText("isRunning = " + anim.isRunning());
isPausedText.setText("isPaused = " + anim.isPaused());
}
|
我們在初始化以后每次修改動畫流的時候都去調用setStatusTexts方法,比如說,當我沒調用cancelAnimation的時候,代碼是這樣的:
1
2
3
4
5
|
; html-script: false ]
public void cancelAnimation(View view) {
anim.cancel();
setStatusTexts();
}
|
演示的結果我們可以從下面上方的動畫中看到。這里我也創建了兩個動畫,一個演示End和cancel效果,另一個演示pause和 Resume效果。可以注意到,動畫的運行狀態在你點擊了End和cancel之后是相同的,就算視覺上看兩者並不一樣。這說明了,你沒法通過動畫的狀態來區分出當前動畫是通過 End 調用還是cancel調用來停止的。這兩者情況下,isStarted和isRunning都會返回false。
而下邊的動畫則顯示了pause和resume調用的效果。當我們通過pause調用去暫停動畫時,isPaused會返回true。然后通過 resume調用去恢復動畫播放后,isPaused也會變成false。可以注意到,圖中如果動畫是自然結束的,動畫的狀態並沒有改變。當然,動畫停止播放后,isStarted和isRunning肯定應該是返回false的。實際上,在動畫自然停止后,如果我們再去調用 isStarted和isRunning他們的的確確會返回false。而動畫中的例子我們並沒有在動畫自然停止后去更新狀態,所以我們並不知道當前的狀態,自然那幾個文本框也就沒有更新。為了能夠更新到最新的狀態,我們可以在動畫中添加AnimatorListener和 AnimatorPauseListener這兩個監聽,這兩個監聽具體的使用方法會是下一講的主要內容。
如果你對教程中的例子有興趣,歡迎去 GitHub 上下載完整代碼。