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