在自定义View中我们通常会重写onMeasure,下面来说说这个onMeasure有什么作用
onMeasure主要用于对于View绘制时进行测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
setMeasuredDimension是设置它的宽度和高度
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;
}
上面用来获取宽高的函数,可以看出这里有3种模式:
UNSPECIFIED
这种模式它的result就是size, size是通过getSuggestedMinimumWidth()和getSuggestedMinimumHeight()获取的, 看看getSuggestedMinimumWidth
protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
通常mBackground是通过外部setBackgroundDrawable调用赋值的. mMinWidth也可以通过外部负责,也可以通过属性赋值
case R.styleable.View_minWidth:
mMinWidth = a.getDimensionPixelSize(attr, 0);
break;
public void setMinimumWidth(int minWidth) {
mMinWidth = minWidth;
requestLayout();
}
通常UNSPECIFIED是不会调用到的.所以我们无需过度关心它的情况.
AT_MOST
AT_MOST对于xml属性中的wrap_content, 就是适用view内容的大小,但是自定义view情况设置wrap_content通常会传入填满父控件的specSize。这点从这里可以看出
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
这显然不是我们希望看到的,所以自定义需要重写onMeasure,来对应这种情况
EXACTLY
EXACTLY模式对应制定的宽高和match_partent, 用来精确的设定宽高.
接下来说说怎么重写onMeasure这个函数,重写onMeasure主要是为了争对设置wrap_content,自定义view填充父容器的情况,所以我们只是争对MeasureSpec.AT_MOST这种情况.
private int measureWidth(int measureSpec){
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = 200;
break;
case MeasureSpec.AT_MOST:
result = Math.min(result,specSize);
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
measureHeight和measureWidth是一样的,注意Math.min(result,specSize)这段代码,用来防止实际父控件的大小比指定的200要小,最终调用:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));
}
最后
在现在这个金三银四的面试季,我自己在网上也搜集了很多资料做成了文档和架构视频资料免费分享给大家【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。