measure getMeasuredWidth/getWidth getRawX/getX的作用和区别

来源:互联网 发布:网络教育 考公务员 编辑:程序博客网 时间:2024/06/05 02:20

本篇博客中参考了以下博文:

Android getWidth和getMeasuredWidth的正解:http://gundumw100.iteye.com/blog/1025191

getX getRawX的区别:http://blog.csdn.net/lovehong0306/article/details/7451507

先看一下关于getWidth方法和getMeasuredWidth方法的说明:
getWidth: Return the width of the your view, in pixels.
getMeasuredWidth: Return the full width measurement information for this view as computed by the most recent call to measure(int, int). This should be used during measurement and layout calculations only. Use getWidth() to see how wide a view is after layout.

官方说明中已经很明确的表示了两个方法的各自作用,getMeasuredWidth只应该用在View控件的测量和布局阶段,而最终呈现出来的View控件的尺寸应该使用getWidth方法来获得。
一个View控件从创建(通过代码或者xml文件创建)到最终呈现在屏幕上要依次经过3个阶段:测量(measure),摆放(layout)和绘制(draw)。
测量阶段就是对measure方法的调用,measure方法会接受两个参数,包含了控件宽度信息的widthMeasureSpec和包含了控件高度信息的heightMeasureSpec。widthMeasureSpec虽然是一个int类型的数值,但是它里面包含了两部分内容,最高2位标识mode,其余位标识size,利用MeasureSpec类提供的getMode方法和getSize方法分别去获得widthMeasureSpec中包含的Mode和Size信息。
可以看一下View的measure方法源码:
<span style="font-size:18px;"> public final void measure(int widthMeasureSpec, int heightMeasureSpec) {        if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||                widthMeasureSpec != mOldWidthMeasureSpec ||                heightMeasureSpec != mOldHeightMeasureSpec) {            // first clears the measured dimension flag            mPrivateFlags &= ~MEASURED_DIMENSION_SET;            if (ViewDebug.TRACE_HIERARCHY) {                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);            }            // measure ourselves, this should set the measured dimension flag back            onMeasure(widthMeasureSpec, heightMeasureSpec);            // flag not set, setMeasuredDimension() was not invoked, we raise            // an exception to warn the developer            if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {                throw new IllegalStateException("onMeasure() did not set the"                        + " measured dimension by calling"                        + " setMeasuredDimension()");            }            mPrivateFlags |= LAYOUT_REQUIRED;        }        mOldWidthMeasureSpec = widthMeasureSpec;        mOldHeightMeasureSpec = heightMeasureSpec;    }</span>
当控件要求forceLayout(要求重新布局,类似要求重绘的invalidate方法)或者widthMeasureSpec或heightMeasureSpec发生了改变时( widthMeasureSpec != mOldWidthMeasureSpec ||          heightMeasureSpec != mOldHeightMeasureSpec),此时会去调用onMeasure方法,在onMeasure方法中会根据Mode和Size来确定一个视图控件的最终呈现时的尺寸。进一步看一下View中的onMeasure方法的源码:
<span style="font-size:18px;">  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));    }</span>

在onMeasure方法中必须要调用setMeasureDimension方法,方法中的两个参数分别代表了后续摆放和绘制阶段时这个视图控件的实际的宽度和高度大小。
第一个参数代表宽度,它是getDefaultSize方法的返回值,那么我们再看一下这个方法的源代码:
<span style="font-size:18px;"> public static int getDefaultSize(int size, int measureSpec) {        int result = size;        int specMode = MeasureSpec.getMode(measureSpec);        int specSize = MeasureSpec.getSize(measureSpec);        switch (specMode) {        case MeasureSpec.UNSPECIFIED:            result = size;            break;        case MeasureSpec.AT_MOST:        case MeasureSpec.EXACTLY:            result = specSize;            break;        }        return result;    }</span>
<span style="font-size:18px;">很显然这个方法的作用就是在两个参数中选择一个作为方法的最终返回值。</span>
<span style="font-size:18px;">第一个参数size的值是getSuggestedMinimumWidth(),它的值取决于我们是否设定了控件MiniumWidth(通过setMiniumWidth)以及控件的背景图像的大小,第二个参数就是widthMeasureSpec,它里面包含了Mode和Size两个信息。接下来,getDefaultSize方法就是根据Mode来判定究竟返回什么值作为最终视图组件的width的值。在这里我们看到了一个非常不妥当的写法,即Mode是AT_MOST或者EXACTLY的时候,它都将widthMeasureSpec中的Size信息作为实际的宽度信息。因为View的measure方法是final的,所以无论是安卓的其它原生视图控件还是我们自己写的自定义视图控件都应该去复写onMeasure方法修订默认的View决定尺寸的这个原则。</span>
<span style="font-size:18px;">那么measure方法中的这两个参数一开始的时候是谁传递给它的呢?简单的讲是<span style="font-family: Arial; line-height: 26px;">这两个参数是由view的父容器传递进来的。具体的内容可以参见大神Aige的博文http://blog.csdn.net/aigestudio/article/details/42989325以及他的其他关于安卓V自定义View的相关博文。</span></span>
<span style="font-family:Arial;font-size:18px;"><span style="line-height: 26px;">所以我们此时再回头品读一下官方对getWidth和getMeasuredWidth方法的说明:</span></span>
<span style="font-family:Arial;font-size:18px;"><span style="line-height: 26px;">getMeasuredWidth: Return the full width measurement information for this view as computed by the most recent call to measure(int, int). This should be used during measurement and layout calculations only. Use getWidth() to see how wide a view is after layout.获得完整的在最近一次通过measure方法得到的视图尺寸信息。该方法只应该用在测量和摆放阶段,获得视图组件实际尺寸应该使用getWidth方法。</span></span>
<span style="font-family:Arial;font-size:18px;"><span style="line-height: 26px;">在使用getWidth方法的时候,应该注意的是,只有经过了测量之后才可以知道该控件的实际尺寸,所以要再measure方法或者重写的onMeasure方法执行之后(例如在onLayout或者onDraw方法中调用),getWidth才会有相应的返回值,不然得到的就仅仅是0。</span></span>
<span style="font-family:Arial;font-size:18px;"><span style="line-height: 26px;">最后说说getX和getRawX。例如我们再一个ImageView控件中,通过onTouchEvent方法中跟随手指移动drawLine的时候,<span style="font-family: Arial; line-height: 26px; color: rgb(51, 51, 51);">getX是获取以该ImageView组件左上角为坐标原点计算的X轴坐标值而</span><span style="font-family: Arial; line-height: 26px; color: rgb(51, 51, 51);">getRawX 获取的是以屏幕左上角为坐标原点计算的X轴坐标值。</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; color: rgb(51, 51, 51);" /></span></span>

0 0
原创粉丝点击