Android进阶之路Android开发Android开发经验谈

Viewgroup绘制流程

2019-03-23  本文已影响15人  奔跑吧李博
ViewGroup的测量、设置位置大小,绘制流程图:
ViewGroup也是继承View,实现了ViewParent和ViewManager接口
public abstract class ViewGroup extends View implements ViewParent, ViewManager 
1.onMeasure()方法流程

Viewgroup调用measure回调onMeasure()方法,通过widthMeasureSpec和heightMeasureSpec获取测量模式和宽高尺寸,如果是测量模式是Exactly,就能直接设置自己的宽高。如果测量模式是wrapcontent,就需要遍历自己所有的子view,就需要先让子childView自己去测量它们的宽高和边距,在累加计算自己的宽高,通过setMeasureDimension()设置最终的宽高。

计算所有ChildView的宽度和高度 然后根据ChildView的计算结果,设置自己的宽和高
    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        /** 
         * 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式 
         */  
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);  
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);  
  
  
        // 计算出所有的childView的宽和高,调用后,它所有的childView的宽和高的值就被确定,也即getMeasuredWidth()有值了。  
        measureChildren(widthMeasureSpec, heightMeasureSpec);  
        /** 
         * 记录如果是wrap_content是设置的宽和高 
         */  
        int width = 0;  
        int height = 0;  
  
        int cCount = getChildCount();  
  
        int cWidth = 0;  
        int cHeight = 0;  
        MarginLayoutParams cParams = null;  
  
        // 用于计算左边两个childView的高度  
        int lHeight = 0;  
        // 用于计算右边两个childView的高度,最终高度取二者之间大值  
        int rHeight = 0;  
  
        // 用于计算上边两个childView的宽度  
        int tWidth = 0;  
        // 用于计算下面两个childiew的宽度,最终宽度取二者之间大值  
        int bWidth = 0;  
  
        /** 
         * 根据childView计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是warp_content时 
         */  
        for (int i = 0; i < cCount; i++)  
        {  
            View childView = getChildAt(i);  
            cWidth = childView.getMeasuredWidth();  
            cHeight = childView.getMeasuredHeight();  
            cParams = (MarginLayoutParams) childView.getLayoutParams();  
  
            // 上面两个childView  
            if (i == 0 || i == 1)  
            {  
                tWidth += cWidth + cParams.leftMargin + cParams.rightMargin;  
            }  
  
            if (i == 2 || i == 3)  
            {  
                bWidth += cWidth + cParams.leftMargin + cParams.rightMargin;  
            }  
  
            if (i == 0 || i == 2)  
            {  
                lHeight += cHeight + cParams.topMargin + cParams.bottomMargin;  
            }  
  
            if (i == 1 || i == 3)  
            {  
                rHeight += cHeight + cParams.topMargin + cParams.bottomMargin;  
            }  
  
        }  
          
        width = Math.max(tWidth, bWidth);  
        height = Math.max(lHeight, rHeight);  
  
        /** 
         * 如果是wrap_content设置为我们计算的值 
         * 否则:直接设置为父容器计算的值 
         */  
        setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth  
                : width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight  
                : height);  
    }  
2.onLayout()方法流程

onLayout方法是ViewGroup对其所有的子childView进行定位摆放。通过遍历子view,获取子view的宽高,再LayoutParams来获取边距,调用每个子view的layout()方法,填入与父view的上下左右边距,就设置了每个子view的位置和大小。

3.viewgroup的绘制流程:

1.绘制背景
2.调用ondraw()绘制自身
3.调用child.ondraw()绘制各个子view
4.绘制滚动条

那么问题又来了,怎么计算一个viewgroup的嵌套层级?

因为viewGroup实现了ViewParent,使用递归的方式计算,只要还有父view,就继续累加记录层数。

    int count = 0;
    public void cal(ViewParent view){
        if(view.getParent() == null){
            Log.i("tag","结束");
        }
        count++;
        ViewParent parentView = view.getParent();
        Log.i("tag","当前层数" + count);
        cal(parentView);
    }
上一篇下一篇

猜你喜欢

热点阅读