Android之View的测量

在上一篇文章中,我们知道,每个View都占据了一个矩形的区域。在现实生活中,我们如果要画一个图形,必须知道它的大小、位置等信息。Android系统也是这样,在绘制View之前,也必须对View进行测量,告诉系统这个视图要画多大。这个过程,在onMeasure()方法中进行。
系统已经封装了一个功能强大的类——MeasureSpec类,通过它来帮助我们测量View。MeasureSpec是一个32位的int值,其中高2位为测量的模式,低30位为测量的大小。在计算中使用位运算的原因是为了提高并优化效率。
![测量模式](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTYwOTE5MTU0MTA2NTAz?x-oss-process=image/format,png)

首先来说第一个模式EXACTLY:
顾名思义,此模式翻译为精确值模式,当我们将控件的宽高指定为wrap_content时,,比如宽度制定为100dp或match_parent时,系统使用的就是EXACTLY模式。

AT_MOST:
最大值模式。当控件的宽高指定为wrap_content时,控件大小一般跟随子控件的内容大小发生改变,此时控件的磁村只要不超过父容器允许的最大尺寸即可。

UNSPECIFIEN:
该属性不指定其大小测量的模式,View想多大就多大,通常情况下在绘制自定义View的时候才会用。

View类默认的onMeasure()方法只支持EXACTLY模式,所以,如果在自定义控件的时候不重写此方法,就只能使用EXACTLY模式。控件可以相应你指定的具体宽高值或者是match_parent属性。而如果要让自定义View支持wrap_content属性,那么就必须重写onMeasure()方法来指定View最后显示时的大小。
例:`@Override
protected void onMeasure(intowidthMeasureSpec, int heightMeasureSpec) 
{
	super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}`

按下Ctrl查看super.onMeasure()方法,可以发现系统最终会调用setMeasuredDimension(intowidthMeasureSpec, int heightMeasureSpec)方法将测量后的宽高值设置进去,从而完成测量工作。所以在重写onMeasure方法后,最终就是要把测量后的宽高值作为参数设置给setMeasuredDimension()方法。
重写onMeasure的代码如下:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec )
{
	setMeasuredDimension(measureWidth(widthMeasureSpec), measureHight(heightMeasureSpec));
}
在onMeasure方法中我们调用自定义的measureWidth方法和measureHeight方法,分别对宽高进行重新定义,参数则是宽和高的MeasureSpec对象,MeasureSpec对象中包含了测量的模式和测量值的大小。
	下面我们具体讲解一下如何自己定义测量值。

第一步,从MeasureSpec对象中提取出具体的测量模式和大小:
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

前面有讲过它们是int值,这里不多说了。

接下来,通过判断测量的模式,给出不同的测量值。当specMode为EXACTLY时,直接使用指定的specSize即可;当specMode为其他两种模式时,需要给它一个默认的大小。特别是如果指定wrap_content属性,即AT_MOST模式,则需要取出我们指定的大小与specSize中最小的一个来作为最后的测量值,MeasureWidth()方法的代码如图下所示:
private int mmeasureWidth(int measureSpec)
{
	int result = 0 ;
	int specMode = MeasureSpec.getMode(measureSpec);
	int specSize = MeasureSpec.getSize(measureSpec);

	if(specMode == MeasureSpec.EXACTLY)
	{
		result = specSize;
	} else 
	{
		result = 200;
		if (specMode == MeasureSpec.AT_MOST )
		{
			result = Math.min(result, specSize);
		}
	}
	return result;
}
measureHeight()方法与measureWidth()基本一致。这里不在复述,稍后会给出Demo地址。
重写onMeasure的目的就是为了给View一个宽高的限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值