想要让系统绘制出你所需要的图形,就必须告诉系统View的大小,所以,在绘制View时,先实现View的onMesure()方法。
在测量View之前,要先了解MeasureSpec这个类,MeasureSpec对象中包含了测量的模式和测量的大小;
测量模式
MeasureSpec.EXACTLY 精确模式:当我们将控件的layout_width属性或者layout_height属性指定为具体值的时候,这时候使用的是MeasureSpec.EXACTLY模式
MeasureSpec.AT_MOST 最大值模式,当我们将控件的layout_width属性或者layout_height属性指定为wrap_content时,控件的大小随子控件的大小变化而变化。
MeasureSpec.UNSPECFIED 不指定大小测量模式,View想多大就多大。
重写onMesure()
查看源码可以知道,super.onMeasure()方法最终将测量所得到的值传给了setMeasuredDimension()供系统调用。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(mesureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
测量宽度:
/**
* 测量宽度
* @param widthMeasureSpec
* @return
*/
private int mesureWidth(int widthMeasureSpec) {
int ret = 0;
int specMode = MeasureSpec.getMode(widthMeasureSpec);//1 获取测量模式
int specSize = MeasureSpec.getSize(widthMeasureSpec);//2 获取测量大小
if (specMode == MeasureSpec.EXACTLY) {//3 如果测量模式为MeasureSpec.EXACTLY,直接将测量值返回
ret = specSize;
} else {//4 其他模式需要给一个默认值
ret = 200;
if (specMode == MeasureSpec.AT_MOST) {//如果为 MeasureSpec.AT_MOST,则需要去除specSize与默认值比较,返回最小值
Math.min(ret, specSize);
}
}
return ret;
}
测量高度:(与宽度几乎一样)
/**
* 测量高度
* @param heightMeasureSpec
* @return
*/
private int measureHeight(int heightMeasureSpec) {
int ret = 0;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
if (specMode == MeasureSpec.EXACTLY) {
ret = specSize;
} else {
ret = 200;
if (specMode == MeasureSpec.AT_MOST) {
Math.min(ret, specSize);
}
}
return ret;
}
注:如果不重写onMeasure()方法,默认情况下,设置wrap_content时,控件会填充父窗体。