Content Transitions In-Depth (part 2)

讓我們從在part1中學到的開始吧。並且進行總結:在Android Lollipop中怎樣才能做出行爲光滑的,無縫的動畫。

What is Content Transition?

Content tarnsition即爲在Activity或者Fragment中進行場景進出的transitioning views,並且這些場景中沒有共享的內容。得益於Google的Material Design設計語言,我們可以在Activity或者Fragment之間進行光滑的,無縫的動畫變換。從Android Lollipop開始,content transition可以在代碼中調用WindowFragment的一些方法進行書寫:

  • setExitTransition() - 當A啓動B時,A的退場動畫;
  • setEnterTransition() - 當A啓動B時,B的進場動畫;
  • setReturnTransiton() - 當B返回到A時,B的退場動畫;
  • setReenterTransition() - 當B返回到A時,A的再進場動畫;

正如我們上面的分析的那樣,我們能夠了解content transition在屏幕上的工作情況,但是一些問題仍待解決。content transition到底是如何被觸發並工作的?可用於Transition的物體(Objects)可以是什麼?framework是如何判定transition views的?在Content transition中,ViewGroup及其children能夠作爲單獨的整體成爲動畫的對象麼?在下面的部分中,我們會對上述問題逐個討論解決。

Content Transitions Under-The-Hood

前面一篇文章中,我們知道作爲一個transition,她又兩個主要的任務:其一是捕獲初始和結束view的狀態;其二是創作兩個不同狀態之間的動畫。Content Transition也不外如是:在content transition動畫創作之前,framework必須要給content transition動畫所需的各種狀態,這樣就能改變每個transition view的是否顯示。具體而言,當Activity A啓動Activity B的時候,以下的一系列的事件(event)將會發生:(在return/reenter transitions中,相同的過程也會發生。)
>

1、Activity A調用startActivity().

a、framwork分析A的view的構造樹(view hierarchy),並且決定當A退場時,哪些view將會成爲tansitioning view set。
b、捕獲A的transition view中的各個view的初始狀態。
c、framework將A的transition view中所有view的狀態設置爲INVISIBLE。
d、在展示的下一幀中,A的exit transition捕獲A的結束狀態。
e、A的exit transition對每個transition view的初始和結束狀態進行比較,並創建出Animator。Animator運作,並進行transition view的動畫展示。

2、Activity B啓動。

a、framwork分析B的view的構造樹(view hierarchy),並且決定當B進場時,哪些view將會成爲tansitioning view set。 這些transition views將會初始化爲INVISIABLE。
b、捕獲B的transition view中的各個view的初始狀態。
c、framework將B的transition view中所有view的狀態設置爲VISIBLE。
d、在展示的下一幀中,B的enter transition捕獲B的結束狀態。
e、B的enter transition對每個transition view的初始和結束狀態進行比較,並創建出Animator。Animator運作,並進行transition view的動畫展示。

通過改變每個view的INVISIBLE和VISIBLE,framework保證了在transition中創造Animation所需的狀態信息。顯而易見,transition中的每個物體必須最少能夠捕獲並且記錄其transition中的初始和結束狀態。幸運的是,抽象類Visibility已經做了這樣的工作:你只需要繼承Visibility,並實現抽象方法onAppear()onDisappear(),這兩個方法會返回Animator對象。在API 21中,官方的具體實現類出現了–Fade,slideExplode。同樣,你可以繼續使用繼承Visibility類實現動畫。具體如何書寫繼承類,這將會在以後的post中進行展示。

Transitioning Views & Transition Groups

我們現在瞭解了在no-shared views中進行場景變換的稱爲content transition。在這部分中,我們將會討論framework是怎樣判定set of views的,並且在使用transition groups時,如何進行判定。

在transition開始之前,framework通過遞歸遍歷Activity(或者Fragment)的Window中的View樹來決定transitioning view的集合。整個搜索過程開始在根view中調用ViewGroup的captureTransitioningView方法,captureTransitioningView的代碼如下:

/** @hide */
@Override
public void captureTransitioningViews(List<View> transitioningViews) {
    if (getVisibility() != View.VISIBLE) {
        return;
    }
    if (isTransitionGroup()) {
        transitioningViews.add(this);
    } else {
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            child.captureTransitioningViews(transitioningViews);
        }
    }
}

這個遞歸的過程比較簡單粗暴:framework跟蹤不同級別的view樹直到它找到一個VISIBLE的葉子view或者是一個transition group。transition group允許我們將整個ViewGroup作爲一個整體來變換。如果一個ViewGroup的isTransitionGroup()

注意到的是:isTransition()將會在下面的情況中返回true:

1、viewGroup擁有背景,或者其transition name不爲空。

方法返回true,則它的所有孩子都將被視爲一個整體一起播放動畫。否則將會繼續遞歸該ViewGroup,其子view也會在動畫的時候被單獨對待。遍歷的最後結果是一個完整的transitioning view的集合將在content transition的時候播放動畫。

需要注意的是:WebView雖然是一個ViewGroup但是沒有被系統認爲是transition view。因此content transition沒有在它上面運行。幸運的是我們可以在return transition之前的某個地方調用:

webView.setTransitionGroup(true)

Conclusion

總的來說,本文涉及到了三個重要的方面:

1.content transition決定非共享元素(即transitioning view)在Activity切換的時候是如何變換的。

2.Content transition的觸發是通過改變transitioning view的visibility來實現的。

3.Transition group讓我們可以將ViewGroup作爲一個整體來變換。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章