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

时间:2021-03-28 05:23:52

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          期间有布局请求          通过布局监听器来实现一系列顺序操作