Android自定义控件View(一) - brave-sailor - 博客园
onMeasure:测量控件的大小(加载布局时Android系统测量子view大小,子view大小通知父view,父view根据自己大小分配子view大小)
MeasureSpec:
MeasureSpec.EXACTLY:父视图希望子视图的大小是specSize中指定的大小;一般是设置了明确的值或者是MATCH_PARENT
MeasureSpec.AT_MOST:子视图的大小最多是specSize中的大小;表示子布局限制在一个最大值内,一般为WARP_CONTENT
MeasureSpec.UNSPECIFIED:父视图不对子视图施加任何限制,子视图可以得到任意想要的大小;表示子布局想要多大就多大,很少使用。
super.onMeasure(widthMeasureSpec, heightMeasureSpec)默认实现
结论:MeasureSpec.AT_MOST和MeasureSpec.EXACTLY走的是同一个分支
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.AT_MOST和MeasureSpec.EXACTLY 分别处理,保证wrap_content效果):Rect mBounds = new Rect(); if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(titleSize); mPaint.getTextBounds(titleText, 0, titleText.length(), mBounds); float textWidth = mBounds.width(); int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight()); width = desired; } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { height = width; } /** * 最后调用父类方法,把View的大小告诉父布局。 */ setMeasuredDimension(width, height);