在自定义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));
}
复制代码