MeasureSpec、自定义View、自定义ViewGroup
32位的,前2位表示测量模式,后30位表示测量值。
MeasureSpec是有自己的Layoutparmes和父容器的尺寸决定的。
自定义View继承View的实现形式下:
xml中设置wrap_content和设置成match_parent具有相同的效果。
原因:View是没有处理WRAP_CONTENT的情况的。
View的onMeasure方法:
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;
}
AT_MOST和EXACTLY下都会设置成测量值。AT_MOST对应的就是wrap_content,EXACTLY对应的就是match_parent,因此设置成wrap_content和match_parent会有相同的效果。
但是为什么会是match_parent的效果呢?
因为View的绘制是从ViewRootImpl开始的,ViewRootImpl的performTraversals分别进行measure、layout、draw过程,绘制会先从顶级View开始,顶级View是一个ViewGroup,它会遍历所有的子View,view的onMeasure中的参数就是ViewGroup传进去的,因此测量值就是match_parent 的效果。
解决方案:
重写view的onMeasure时,在AT_MOST的模式下,设置成一个默认值和测量值两者的小的值。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = 100;
int desiredHeight = 100;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
}
自定义ViewGroup的时候会不会调用onDraw方法?
如果自定义的ViewGroup的背景backgroud为空,就不会调用onDraw。相反如果backgroud不为空就会调用onDraw方法。
为了让自定义的ViewGroup会调用onDraw方法,可以通过如下方式:
1、设置ViewGroup的backgroud
2、调用setWillNotDraw(false),去掉其WILL_NOT_DRAW这个Flag