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作为一个整体来变换。

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