这两天比较空闲,所以就在研究自定义view。写了几个demo,但是由于有些资料看的不是很懂,所以感觉就比较烦躁。尤其是在onMeasure中的很多参数看的不是很懂,所以今天重新来看了这个方法。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widSpecmode=MeasureSpec.getMode(widthMeasureSpec);
int widSpecsize=MeasureSpec.getSize(widthMeasureSpec);
int heiSpecmode=MeasureSpec.getMode(heightMeasureSpec);
int heiSpecsize=MeasureSpec.getSize(heightMeasureSpec);
int width = 0,height = 0;
if(widSpecmode==MeasureSpec.EXACTLY)
{
width=widSpecsize;
}else
{
mPaint.setTextSize(textsize);
mPaint.getTextBounds(text, 0, text.length(), mBound);
if(widSpecmode==MeasureSpec.AT_MOST)
{
int descre=mBound.width()+getPaddingRight()+getPaddingLeft();
width=descre;
}
}
if(heiSpecmode==MeasureSpec.EXACTLY)
{
height=heiSpecsize;
}else
{
mPaint.setTextSize(textsize);
mPaint.getTextBounds(text, 0, text.length(), mBound);
if(heiSpecmode==MeasureSpec.AT_MOST)
{
int des=mBound.height()+getPaddingBottom()+getPaddingTop();
height=des;
}
}
setMeasuredDimension(width, height);
}
这个方法里面我之前一直疑惑的是,该方法在重写的时候,默认传入的widthMeasureSpec、heightMeasureSpec是怎么来的?有什么用?后来经过百度参考了一些资料后,是这么解释的。当执行该方法时,父控件会传递一个元数据,告诉子控件可获得的空间和对该空间的描述。至于widSpecmode,就是我们根据该数据,判断测量模式。
测量模式分3种:EXACTLY、AT_MOST、UNSPECIFIED
EXACTLY: 精确值,如:我们平常用的12dp或者match_parent
AT_MOST:子控件所能获得的最大值,如:warp_content
UNSPECIFIED:子控件想要多大就要多大,父控件没有任何限制,如:100000dp就属于此类,基本没有任何意义
所以在EXACTLY的情况下,宽度和高度就可以设置为传入的高度或宽度。然而在AT_MOST的情况下,不光需要获得空间本身内容的大小,还需要加上padding的值。才是此控件的大小。
然后我们就可以调用setMeasuredDimension(width, height); 告诉父控件我们需要多大的尺寸。
关于onMeasure我能想到的就这么多,这这里我顺便说一下关于getTextBounds这个方法,刚开始自己也不是很理解这个方法的作用。不过后来查了很多资料后,发现是这么说的,该方法可以计算出字符串的准确高度和宽度,并缓存到mBound里面,这样当我们需要的时候,就可以直接从mBound里面取值了。
paint = findViewById(R.id.hello_world).getPaint();
paint.getTextBounds(text, 0, text.length(), bounds);
int width = bounds.width();
参考:http://blog.sina.com.cn/s/blog_61fbf8d10100zzoy.html
http://blog.csdn.net/a739697044/article/details/30234161