Measure的中文意思就是测量。所以它的作用就是测量View的大小。
当控件的父元素正要放置该控件时调用.父元素会问子控件一个问题,“你想要用多大地方啊?”,然后传入两个参数——宽详细测量值(widthMeasureSpec)和高详细测量值(heightMeasureSpec)。这两个参数指明控件可获得的空间以及关于这个空间描述的元数据,可以把详细测量值理解为视图View想要的大小说明。对于详细测量值(measureSpec)需要两样东西来确定它,那就是大小(size)和模式(mode)。而measureSpec,size,mode他们三个的关系,都封装在View类中的一个内部类里,名叫MeasureSpec。
onMeasure():
知道了widthMeasureSpec和heightMeasureSpec是什么以后,我们就可以来看onMeasure方法了:
/**
* 这个方法需要被重写,应该由子类去决定测量的宽高值,
*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
} 在onMeasure中只调用了setMeasuredDimension()方法,接受两个参数,这两个参数是通过getDefaultSize方法得到的。getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),这里就是获取最小宽度作为默认值,然后再根据具体的测量值和选用的模式来得到widthMeasureSpec。heightMeasureSpec同理。之后将widthMeasureSpec,heightMeasureSpec传入setMeasuredDimension()方法。
setMeasuredDimension():
/**
* 这个方法必须由onMeasure(int, int)来调用,来存储测量的宽,高值。
*/
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
} 这个方法就是我们重写onMeasure()所要实现的最终目的。它的作用就是存储我们测量好的宽高值。这下思路清晰了,现在的任务就是计算出准确的measuredWidth和heightMeasureSpec并传递进去,我们所有的测量任务就算完成了。
源码中使用的getDefaultSize()只是简单的测量了宽高值,在实际使用时需要精细、具体的测量。而具体的测量任务就交给我们在子类中重写的onMeasure方法。
在子类中重写的onMeasure:
在测量之前首先要明确一点,需要测量的是一个View(例如TextView),还是一个ViewGroup(例如LinearLayout),还是多个ViewGroup嵌套。如果只有一个View的话我们就测量这一个就可以了,如果有多个View或者ViewGroup嵌套我们就需要循环遍历视图中所有的View。
下面列出一个最简单的小例子,写一个自定义类CostomViewGroup继承自ViewGroup,然后重写它的构造方法,onMeasure和onLayout方法。
最后看一下自定义ViewGroup中的onMeasure方法的内容:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//调用ViewGroup类中测量子类的方法
measureChildren(widthMeasureSpec, heightMeasureSpec);
//调用View类中默认的测量方法
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
} 每一个MeasureSpec有一个尺寸(size)和一个模式(mode)构成。MeasureSpecs这个类提供了把一个<size, mode>的元组包装进一个int型的方法,从而减少对象分配。当然也提供了逆向的解析方法,从int值中解出size和mode。
有三种模式:
MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
通过int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式,
通过int size = MeasureSpec.getSize(widthMeasureSpec)得到尺寸。
通过getWidth() 得到 View在设定好布局后整个View的宽度,
通过getMeasuredWidth() 得到 对View上的內容进行测量后得到的View內容实际的宽度。
onMeasure方法是Android中用于测量View大小的关键方法。它结合MeasureSpec中的模式(mode)和大小(size)来确定View的尺寸。在自定义View或ViewGroup时,需要重写onMeasure以指定合适的尺寸。在测量过程中,可以通过MeasureSpec的getMode和getSize获取模式和大小,并使用setMeasuredDimension设置测量结果。当处理ViewGroup时,通常需要遍历并测量其子View。

1173

被折叠的 条评论
为什么被折叠?



