ViewRootImpl--
一、Measure (performMeasure)
1.measureSpace
ViewRootImpl--getRootMeasureSpec(),返回了一个int类型的measureSpace(以下简称ms),ms是个32位的int数值,他的前2位表示mode,后30位表示尺寸。
例:
00 000000000000000000000000000000
specMode ↑ specSize
SpecMode分为3种EXACTLY、AT_MOST、UNSPECIFIED
/**
* Measure specification mode: The parent has not imposed any constraint
* on the child. It can be whatever size it wants.
*/
00000000000000000000000000000000
1.父容器不对view做任何限制,系统内部使用
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
/**
* Measure specification mode: The parent has determined an exact size
* for the child. The child is going to be given those bounds regardless
* of how big it wants to be.
*/
01000000000000000000000000000000
2.父容器检测出view的大小,view的大小就是SpecSize
子控件的LayoutParams的match_parent 以及 固定大小
public static final int EXACTLY = 1 << MODE_SHIFT;
/**
* Measure specification mode: The child can be as large as it wants up
* to the specified size.
*/
10000000000000000000000000000000
3.父容器指定一个指定大小,view大小不能超过这个值, LayoutParams wrap_content
public static final int AT_MOST = 2 << MODE_SHIFT;
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
通过View--makeMeasureSpec()我们可以知道,
mode + size = MeasureSpec
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
/**
* Creates a measure specification based on the supplied size and mode.
*
* The mode must always be one of the following:
* <ul>
* <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li>
* <li>{@link android.view.View.MeasureSpec#EXACTLY}</li>
* <li>{@link android.view.View.MeasureSpec#AT_MOST}</li>
* </ul>
*
* <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's
* implementation was such that the order of arguments did not matter
* and overflow in either value could impact the resulting MeasureSpec.
* {@link android.widget.RelativeLayout} was affected by this bug.
* Apps targeting API levels greater than 17 will get the fixed, more strict
* behavior.</p>
*
* @param size the size of the measure specification
* @param mode the mode of the measure specification
* @return the measure specification based on size and mode
*/
public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
@MeasureSpecMode int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
通过对MODE_MASK和~MODE_MASK 取 & 操作,取得mode 和 size
MODE_MASK = 11000000000000000000000000000000
~MODE_MASK = 00111111111111111111111111111111
View的测量:
一、确定DecorViewde的MesasureSpec
DecorView的MesaureSpec有窗口大小和自身LayoutParams决定,遵循如下规则:
1.LayoutParams.MATCH_PARENT:精确模式,窗口大小
2.LayoutParams.WRAP_CONTENT:最大模式,最大为窗口大小
3.固定模式:精确模式,大小为LayoutParams大小
二、确定View的MeasureSpec
![](https://img.haomeiwen.com/i1972107/f198d9afc31f3c99.png)
measure--onMeasure--setMeasureDimension--setMeasureDimensionRaw
ViewGroup的测量:
measure--onMeasure(测量子控件宽高)--setMeasureDimension--setMeasureDimensionRaw(保存自己的宽高)
二、Layout (performLayout)
1.View类型:
调用viwe.layout确定自身位置,即确定mLeft, mTop, mRight, mBottom
2.ViewGroup类型:
layout(来确定自己位置,4个点的位置)--onLauout(进行子view的布局)
三、Draw ( performDraw )
1.绘制背景 drawBackground(canvas)
2.绘制自己 onDraw(canvas)
3.绘制子View dispatchDraw(canvas) (view不会有)
4.绘制前景,如滚动条等装饰 onDrawForefround(canvas)
总结
onMeasure---onLayout---onDraw
当我们自定义的是容器的时候,需要去实现onLayout方法,自定义view的时候,可以不用重写它。
onDraw方法,可选,如果onDraw中放的都是系统控件,可以不用重写。
网友评论