addView 源码中方法调用顺序的迷惑 :
public void addView(View child,int index, LayoutParams params) {
if (DBG) {
System.out.println(this +" addView");
}
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
requestLayout();
invalidate(true);
addViewInner(child, index, params, false);
}
为什么在addViewInner(); 前要使用requestLayout(); addViewInner里面会调用requestLayout(); 这样逻辑上是不是重复了。
public void requestLayout() {
mPrivateFlags |= FORCE_LAYOUT;
mPrivateFlags |= INVALIDATED;
if (mLayoutParams != null) {
mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
}
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
}
requestLayout();的很重要的一步操作是给mPrivateFlags赋上FORCE_LAYOUT值。
if (mParent != null && !mParent.isLayoutRequested()) 这一步逻辑是。
public boolean isLayoutRequested() {
return (mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT;
}
由于requestLayout() 是从当前view往上传递来申请重新layout布局。如果父容器的mPrivateFlags不包含FORCE_LAYOUT。执行父容器的requestLayout();
这里父容器mPrivateFlags包含FORCE_LAYOUT,所以不会向上传递申请重新layout布局。
那么 mPrivateFlags 什么时候清空FORCE_LAYOUT值呢?在view 的layout 方法最后:
public void layout(int l, int t, int r, int b) {
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
boolean changed = setFrame(l, t, r, b);
if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~LAYOUT_REQUIRED;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList<OnLayoutChangeListener> listenersCopy =
(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
int numListeners = listenersCopy.size();
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
mPrivateFlags &= ~FORCE_LAYOUT;
}
mPrivateFlags &= ~FORCE_LAYOUT 清空了FORCE_LAYOUT。也就是 这个view layout 之后 FORCE_LAYOUT会被清空。
vg.addView(new Son(MainActivity.this));
vg.addView(new Son(MainActivity.this));
vg.addView(new Son(MainActivity.this));
站在父容器vg 的角度看,会引发如下流程:
=view1=
1. requestLayout(); //发出layout消息, 触发vg 的 onMeasure(), onLayout()
2. invalidate(true); //发出重绘制消息,触发vg 的draw()
3. child.setLayoutParams(params); //会触发child的layout(), 不会向父容器方向传递触发vg的layout。
因为被步骤1的父容器layout 的 mPrivateFlags == FORCE_LAYOUT阻断。
=view2=
4. requestLayout(); // 不会发出layout消息,不会触发vg 的 onMeasure(), onLayout()。
因为被步骤1的父容器layout 的 mPrivateFlags == FORCE_LAYOUT阻断。
5. invalidate(true); //不会发出重绘消息,不会触发vg 的draw()。
因为被步骤2的 mPrivateFlags DRAWN / DRAWING_CACHE_VALID/INVALIDATED阻断。
6. child.setLayoutParams(params); //会触发child的layout(), 不会向父容器方向传递触发vg的layout。
因为被步骤1的父容器layout 的 mPrivateFlags == FORCE_LAYOUT阻断。
=view3=
7. requestLayout(); // 不会发出layout消息,不会触发vg 的 onMeasure(), onLayout()。
因为被步骤1的父容器layout 的 mPrivateFlags == FORCE_LAYOUT阻断。
8. invalidate(true); //不会发出重绘消息,不会触发vg 的draw()。
因为被步骤2的 mPrivateFlags DRAWN / DRAWING_CACHE_VALID/INVALIDATED阻断。
9. child.setLayoutParams(params); //会触发child的layout(), 不会向父容器方向传递触发vg的layout。
被步骤1的父容器layout 的 mPrivateFlags == FORCE_LAYOUT阻断。
所以父类容器以及子view 的 onMeasure(), onLayout() 都只会被各调用一次。
demo 地址: