Android轉場動畫深度解析(2)

大頭呆發表於2017-09-09

緊接著上一篇介紹了Scene和Transition的基本用法後,這篇開始介紹如何運用這些到轉場動畫中。從A頁面到B頁面,再從B頁面返回到A頁面,這就是一個完整的轉場過程。而轉場動畫就是負責來優雅地協調處理好這個過程的。

Content Transition

Content Transition就是最常見的轉場動畫了。為了方便大家理解,我們先來上個圖。

Android轉場動畫深度解析(2)
部分程式碼:

源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);
複製程式碼

再次執行程式,日誌資訊如下:

Android轉場動畫深度解析(2)
原來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>
複製程式碼

修改後效果如下:

Android轉場動畫深度解析(2)
日誌也顯示現在是序列執行了:
Android轉場動畫深度解析(2)

生命週期分析

保持上面的列印資訊不變,我們增加兩個Activity的生命週期日誌資訊,序列結果如下:

Android轉場動畫深度解析(2)
並行如下:

Android轉場動畫深度解析(2)
可以得到如下資訊:

  • 在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中很有特色的動畫了。

相關文章