Android布局动画梳理之LayoutTransition源码追踪


Android系统的布局动画可以按如下脉络进行梳理

1、按时间点分类
     版本4.0之前可能没有,4.0或以上有LayoutTransition,4.4.2或以上有scenes+transition

2、按动作划分
     child自身的动画
     child移动的动画
     可能的组合
          被增删的child的自身动画
          被影响的其他child的自身动画及移动动画

3、按涉及的部件划分
     ViewGroup或其子类
     LayoutTransition

4、需要梳理的问题
     被增删的child的自身动画-------就是单个view的动画,这个无需梳理
     受影响的其他child的自身动画
          何时、怎样调用item的动画?
          动画模板是怎样构建的?child怎样拷贝这个模板的?
     受影响的其他child的移动动画(重点)
          是不是有一个预布局?
               留意一个监听布局改变的listener
          child移动动画的初始值和结束值是怎样计算的?又怎样调用的?
          可能只有ViewGroup的增删动作才触发动画?
          如果adapter的数据变化,又怎样才能触发动画?
          4.4.2之后的框架是怎么回事?
      其他child的自身动画和移动动画是怎样叠加的?

5、相关知识点
     都有哪些布局计算或操作?比如requestLayout()之类
     View体系中各个部件之间是怎样通过设置Listener来互相通信及同步的?

6、梳理策略
     从ApiDemo里面的LayoutTransition开始
     其后梳理由scenes+transition构成的Transitions framework



以下是从ViewGroup.addView()追踪到LayoutTransition源码的过程及结论

ViewGroup类

     addView(View child) / addView(View child, int index) / addView(View child, int width, int height)
          addView(View child, int index, LayoutParams params)
               addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout)
                    mTransition.addChild(this, child) //从这里进入LayoutTransition类源码
                    child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
                    onViewAdded(child);//这里可能只是一个回调通知而已
                         mOnHierarchyChangeListener.onChildViewAdded(this, child);
                    childHasTransientStateChanged(child, true);

     removeView(View view) //和addView基本类似
          removeViewInternal(int index, View view)
               mTransition.removeChild(this, view);
               addDisappearingView(view);
               view.dispatchDetachedFromWindow();
               removeFromArray(index);
               onViewRemoved(view);
          requestLayout();

     结论
          在ViewGroup中应该只是一个增删child及重新布局的刷新操作
          没有看到受影响的其他child的相关操作,这些可能都在LayoutTransition里面


LayoutTransition类

     addChild(ViewGroup parent, View child)
          addChild(ViewGroup parent, View child, boolean changesLayout)
               runChangeTransition(parent, child, APPEARING);
                    loop: setupChangeAnimation(parent, changeReason, baseAnimator, duration, child);设置其他child的动画
                         anim.setTarget(child);anim.setupStartValues();//设置当前child状态为动画初始值
                              PropertyValuesHolder.setupValue(Object target, Keyframe kf) //通过反射机制获取target的属性值
                         View.OnLayoutChangeListener(){anim.setupEndValues();} //在重新布局时获取动画结束值
                         parent.requestTransitionStart(LayoutTransition.this);//估计在这里启动动画
                    loop: setupChangeAnimation((ViewGroup)parentParent, changeReason, parentAnimator, duration, tempParent);设置各级祖先层的动画
               runAppearingTransition(parent, child);//这里面实际上没有什么Transition,仅仅是启动用户设置的mAppearingAnim

     removeChild(ViewGroup parent, View child)
          removeChild(ViewGroup parent, View child, boolean changesLayout)
               runChangeTransition(parent, child, DISAPPEARING);//和addChild共用一个函数,只是选择了另一个动画
               runDisappearingTransition(parent, child);//里面没有Transition,直接启动mDisappearingAnim

     结论
          增删child导致其他child的布局发生变化,下面是“其他child”的移动动画构建流程
               在布局修改前保存child状态为Transition动画的初始值
               设置一个布局改变监听器
               在布局改变后(可能在绘制前)保存child状态为Transition动画的结束值
               启动动画
          其他child的自身动画和移动动画是怎样叠加的?直接先后调用runChangeTransition和runAppearingTransition
          期间有布局请求
          通过布局监听器来实现一系列顺序操作



你可能感兴趣的:(Android)