View 在屏幕上要显示出来的要经过measure(计算)和 layout(布局)
<span style="font-size:18px;"> @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}</span>
1、详解onMeasure()方法 参数
一般情况下,我们可以根据自身定义大小。在控件的父元素要放置该控件时,父元素会问子控件一个问题,“你想要多少的地方” ,然后传入两个参数,---widthMeasureSpace 和 heightMeasureSpace.这两个控件可获得的控件以及关于这个空间描述的元数据。
onMeasure(int widthMeasureSpec, int heightMeasureSpec)中,两个参数的作用: widthMeasureSpec和heightMeasureSpec这两个int类型的参数,看名字应该知道是跟宽和高有关系,但它们其实不是宽和高,而是由宽、高和各自方向上对应的模式来合成的一个值:其中,在int类型的32位二进制位中,31-30这两位表示模式,0~29这三十位表示宽和高的实际值.其中模式一共有三种,被定义在Android中的View类的一个内部类中:View.MeasureSpec:
①UNSPECIFIED:表示默认值,父控件没有给子view任何限制。------二进制表示:00
②EXACTLY:表示父控件给子view一个具体的值,子view要设置成这些值的大小。------二进制表示:01
③AT_MOST:表示父控件个子view一个最大的特定值,而子view不能超过这个值的大小。------二进制表示:10
更好的方法是你传递view的高度和宽度到setMeasureDimension() 方法里,这样可以直接告诉父控件,需要多大的地方放置子控件。
2、代码如下:
2.1 、方式一
<span style="font-size:18px;"> @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 声明一个临时变量来存储计算出的测量值
int resultWidth = 0;
// 获取宽度测量规格中的mode
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
// 获取宽度测量规格中的size
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
/*
* 如果爹心里有数
*/
if (modeWidth == MeasureSpec.EXACTLY) {
// 那么儿子也不要让爹难做就取爹给的大小吧
resultWidth = sizeWidth;
}
/*
* 如果爹心里没数
*/
else {
// 那么儿子可要自己看看自己需要多大了
resultWidth = mBitmap.getWidth();
/*
* 如果爹给儿子的是一个限制值
*/
if (modeWidth == MeasureSpec.AT_MOST) {
// 那么儿子自己的需求就要跟爹的限制比比看谁小要谁
resultWidth = Math.min(resultWidth, sizeWidth);
}
}
int resultHeight = 0;
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
if (modeHeight == MeasureSpec.EXACTLY) {
resultHeight = sizeHeight;
} else {
resultHeight = mBitmap.getHeight();
if (modeHeight == MeasureSpec.AT_MOST) {
resultHeight = Math.min(resultHeight, sizeHeight);
}
}
// 设置测量尺寸
setMeasuredDimension(resultWidth, resultHeight);
} </span>
2.2、方式二
<span style="font-size:18px;"> @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = (int) mPaint.measureText(text) + getPaddingLeft() + getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by
// measureSpec
result = Math.min(result, specSize);
}
}
return result;
}
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
mAscent = (int) mPaint.ascent();
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = (int) (-mAscent + mPaint.descent()) + getPaddingTop() + getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by
// measureSpec
result = Math.min(result, specSize);
}
}
return result;
} </span>