美文网首页Android开发
addView方法分析

addView方法分析

作者: gczxbb | 来源:发表于2018-04-28 15:34 被阅读111次

    ViewGroup的addView方法,Android开发中最常用的方法之一。它是容器视图特有的方法,不在基类View中。该方法向容器中增加子节点,视图树结构中,每个视图节点可以有多个子节点,但是,每个子节点只能有一个父节点。本文主要分析addView方法如何添加子节点,再看一下和它相关的常用方法。在ViewGroup类,它有三个重载方法。

    public void addView(View child) {
        addView(child, -1);
    }
    

    index是插入容器内部子视图数组的索引位置,默认<0,插入数组尾部。

    public void addView(View child, int index) {
        LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = generateDefaultLayoutParams();
            if (params == null) {  //抛出异常
            }
        }
        addView(child, index, params);
    }
    

    如果布局参数是空,生成默认值,最终的布局参数一定要存在。

    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, 
                        LayoutParams.WRAP_CONTENT);
    }
    

    宽高是WRAP_CONTENT类型。

    public void addView(View child, int index, LayoutParams params) {
        requestLayout();
        invalidate(true);
        addViewInner(child, index, params, false);
    }
    

    该方法将依次调用另外三个方法,分别是requestLayout方法、invalidate方法、和addViewInner方法。前两个方法视图重绘,将在其他文章单独分析。

    private void addViewInner(View child, int index, LayoutParams params,
                boolean preventRequestLayout) {
        //child的mParent存在,抛出异常,一个视图不能加到两个父视图节点
        ...
        //检查生成LayoutParams
        if (!checkLayoutParams(params)) {
            params = generateLayoutParams(params);
        }
        //设置LayoutParams
        if (preventRequestLayout) {
            child.mLayoutParams = params;
        } else {
            child.setLayoutParams(params);
        }
        //index小于0时,插入点在mChildrenCount,即子View数组的尾部
        if (index < 0) {
            index = mChildrenCount;
        }
        //插入数组
        addInArray(child, index);
        //为child设置mParent
        if (preventRequestLayout) {
            child.assignParent(this);
        } else {
            child.mParent = this;
        }
        
        AttachInfo ai = mAttachInfo;
        if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
            child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
            ...
        }
        ...
        dispatchViewAdded(child);
        ...
    }
    

    首先,查它子视图内部mParent引用,一个子视图不可以同时挂两个父节点,抛出IllegalStateException异常。
    然后,设置子视图内部LayoutParams。addInArray方法,加入内部子视图数组,同时更新数量。设置子视图父节点mParent,即当前容器视图,
    最后,子视图dispatchAttachedToWindow方法,初始化内部AttachInfo对象。同时,在该方法中,调用子视图的onAttachedToWindow方法,表示已经attached到窗体。

    下面看一下几个类似的方法。
    removeView方法。
    addViewInLayout方法、removeViewInLayouy方法。
    attachViewToParent方法、detachViewFromParent方法。


    相似方法分析

    removeView方法和addView方法是一对,前者是删除视图,后者是增加视图。

    public void removeViewAt(int index) {
        removeViewInternal(index, getChildAt(index));
        requestLayout();
        invalidate(true);
    }
    

    删除index索引的视图,和addView一样,该方法也会调用requestLayout方法和invalidate方法,视图重绘。getChildAt方法,根据索引从数组查找视图。

    private void removeViewInternal(int index, View view) {
        if (view.getAnimation() != null ||
                    (mTransitioningViews != null && mTransitioningViews.contains(view))) {
            addDisappearingView(view);
        } else if (view.mAttachInfo != null) {
            view.dispatchDetachedFromWindow();
        }
        ...
        removeFromArray(index);      
        dispatchViewRemoved(view);    
        ...
    }
    

    调用子视图dispatchDetachedFromWindow方法,onDetachedFromWindow方法。子视图主动调用,表示自己detached窗体,可以重写做一些操作。
    removeFromArray方法,从数组中删除索引处的视图。

    addViewInLayout和removeViewInLayou方法是一对,和前面两个方法类似,也会调用前面的addViewInner和removeViewInternal方法,区别是,不会调用重绘方法。
    attachViewToParent和detachViewFromParent方法是一对,它们仅调用数组操作的addInArray和removeFromArray方法,区别是,不会重绘,也不会有子视图的attach和detached回调,仅仅是数据的变化。在RecyclerView源码中会遇到这两个方法,这里就不详细介绍了。


    总结

    addView和removeView方法,操作容器内的子视图数组,触发视图重绘制,触发子视图attach和detached窗体回调。
    addViewInLayout和removeViewInLayou方法,与上面一样,只是不会重绘视图。
    attachViewToParent和detachViewFromParent方法,只会操作容器内的子视图数组。


    任重而道远

    相关文章

      网友评论

        本文标题:addView方法分析

        本文链接:https://www.haomeiwen.com/subject/nniwlftx.html