onMeasure方法简述

来源:互联网 发布:算法分析与设计吕国英 编辑:程序博客网 时间:2024/05/16 05:54

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內容实际的宽度。


0 0
原创粉丝点击