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);
}