1, View三部曲
在oncreate方法中加载解析完xml资源创建view对象之后,Activity中的makeVisible方法会将这些对象依次测量,确定位置并且显示在幕布上。总体的流程图如下,
重点分析onMeasure,onLayout,和onDraw方法。
1.1 onMeasure
measure是测量的意思,那么onMeasure()方法顾名思义就是用于测量视图的大小的.
1.1.1 view
首先看没有子view的测量方法.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
MeasureSpec的值由specSize和specMode共同组成的,其中specSize记录的是大小(后30位),specMode记录的是规格(前2位). specMode一共有三种类型。
变量widthMeasureSpec和heightMeasureSpec都是ViewRoot的performTraversals方法中获取的,
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
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;
}
根视图总是会充满全屏的。
1.1.2 ViewGroup
既然子view都实现了o