緊接著上一篇介紹了Scene和Transition的基本用法後,這篇開始介紹如何運用這些到轉場動畫中。從A頁面到B頁面,再從B頁面返回到A頁面,這就是一個完整的轉場過程。而轉場動畫就是負責來優雅地協調處理好這個過程的。
Content Transition
Content Transition就是最常見的轉場動畫了。為了方便大家理解,我們先來上個圖。
部分程式碼:源Activity:
Slide slide=new Slide();
slide.setDuration(3000);
slide.setSlideEdge(Gravity.BOTTOM);
getWindow().setExitTransition(slide);
Explode explode = new Explode();
explode.setDuration(3000);
explode.setMode(Visibility.MODE_IN);
getWindow().setReenterTransition(explode);
複製程式碼
目標Activity:
Slide slideEnter=new Slide();
slideEnter.setDuration(1500);
slideEnter.setSlideEdge(Gravity.RIGHT);
getWindow().setEnterTransition(slideEnter);
Slide slide=new Slide();
slide.setDuration(1500);
slide.setSlideEdge(Gravity.RIGHT);
getWindow().setReturnTransition(slide);
複製程式碼
然後在A頁面呼叫方法跳到B頁面:
Intent intent = new Intent(this, BActivity.class);
ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(this);
startActivity(intent, activityOptionsCompat.toBundle());
複製程式碼
可以看到一共可以設定四個Transition:
-
(1)setExitTransition() - 當A 跳轉到 B時,A中的View退出場景的效果(預設Null)
-
(2)setEnterTransition() - 當A 跳轉到 B時,B中的View進入場景的效果(預設Fade)
-
(3)setReturnTransition() - 當B 返回 A時,B中的View退出場景的效果(預設同EnterTransition)
-
(4)setReenterTransition() - 當B 返回 A時,A中的View進入場景的效果(預設同ExitTransition)
以上這個過程同樣可以看做是Transition作用在Scene上的一系列效果,只不過這裡的Scene從上一篇中的單一佈局換成了Window。不過細心的同學可能發現了,明明我為四個過程都設定動畫效果,可為什麼ExitTransition沒有生效呢?接下來我們為每個Transition加入監聽,看看動畫的執行流程。下面是其中一個的程式碼,其他三個都一樣:
Explode explode = new Explode();
explode.setDuration(3000);
explode.setMode(Visibility.MODE_IN);
explode.addListener(new Transition.TransitionListener(){
@Override
public void onTransitionStart(Transition transition) {
Log.d("Transitions--","ReenterTransitionStart");
}
@Override
public void onTransitionEnd(Transition transition) {
Log.d("Transitions--","ReenterTransitionEnd");
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
getWindow().setReenterTransition(explode);
複製程式碼
再次執行程式,日誌資訊如下:
原來A頁面的退出動畫和B頁面的進入動畫、B頁面的返回動畫和A頁面的重現動畫是並行執行的。也就是說A頁面的ExitTransition不是沒有執行,而是在它執行的時候,B頁面已經覆蓋上來,並且EnterTransition已經同時在執行了,這時A頁面已經不可見了。這也是Android預設的轉場動畫執行流程。 那問題來了,如果想要序列執行該怎麼辦呢? 有兩種方法: 在設定Transition的時候同時設定不允許Transition重疊,也就是並行執行:getWindow().setAllowEnterTransitionOverlap(false);
getWindow().setWindowAllowReturnTransitionOverlap(false);
複製程式碼
或者在主題檔案全域性設定這個屬性,這樣無疑更好,即減少了程式碼又保證了應用視覺效果的統一:
<item name="android:windowAllowEnterTransitionOverlap">false</item>
<item name="android:windowAllowReturnTransitionOverlap">false</item>
複製程式碼
修改後效果如下:
日誌也顯示現在是序列執行了:生命週期分析
保持上面的列印資訊不變,我們增加兩個Activity的生命週期日誌資訊,序列結果如下:
並行如下: 可以得到如下資訊:- 在A頁面的onPause執行前,ExitTransition就已經開始執行了
- Transition不會阻塞BActivity的生命週期,儘管是序列執行的,即使ExitTransition沒結束,BActivity已經執行完OnResume了。
- ReturnExitTransition需要等到AActivity OnStart執行完才開始執行,而且ReturnExitTransition會阻塞AActivity的生命週期,AActivity的OnResume會等到ReturnExitTransition執行完再執行。關於這點可以簡要說明下:直接呼叫Finish不會有動畫直接結束掉,需要執行
onBackPressed()
才會有ReturnExitTransition。看原始碼就很明顯了:
public void onBackPressed() {
if (mActionBar != null && mActionBar.collapseActionView()) {
return;
}
if (!mFragments.getFragmentManager().popBackStackImmediate()) {
finishAfterTransition();
}
}
複製程式碼
總結
最後簡單分析下轉場動畫的大致流程(以slide為例),看過上一篇文章的同學應該很好理解:
1.從DecoerView開始,依次遍歷獲得當前Window上的檢視樹裡的所有View
2.執行captureStartValues(TransitionValues transitionValues),捕獲View開始狀態的一些屬性(visibility,Parent,LocationOnScree)
3.設定所有的VIew為INVISIBLE。
4.執行captureEndValues(TransitionValues transitionValues),捕獲View結束狀態的一些屬性(visibility,Parent,LocationOnScree)
5.比較屬性的不同,建立屬性動畫。下一個過程就是返回屬性動畫並執行了。
複製程式碼
這是ExitTransiton的流程,其他三個也差不多。下一篇將會講帶共享元素的轉場動畫,也是material design中很有特色的動畫了。