addView 源码调用顺序的迷惑

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 地址:


http://download.csdn.net/detail/javalive09/6867681


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值