getMeasuredWidth和getWidth的区别

简介: View的getWidth()和getMeasuredWidth()有什么区别吗?View的高宽是由View本身和Parent容器共同决定的。getMeasuredWidth()和getWidth()分别对应于视图绘制的measure和layout阶段。

View的getWidth()和getMeasuredWidth()有什么区别吗?

View的高宽是由View本身和Parent容器共同决定的。
getMeasuredWidth()getWidth()分别对应于视图绘制的measure和layout阶段。getMeasuredWidth()获取的是View原始的大小,也就是这个View在XML文件中配置或者是代码中设置的大小。getWidth()获取的是这个View最终显示的大小,这个大小有可能等于原始的大小,也有可能不相等。比如说,在父布局的onLayout()方法或者该View的onDraw()方法里调用measure(0, 0),二者的结果可能会不同(measure中的参数可以自己定义)。

getWidth()

/**
     * Return the width of the your view.
     * @return The width of your view, in pixels.
     */
    @ViewDebug.ExportedProperty(category = "layout")
    public final int getWidth() {
        return mRight - mLeft;
    }

从源码上看,getWidth()是根据mRightmLeft之间的差值计算出来的,需要在布局之后才能确定它们的坐标,也就是说布局后在onLayout()方法里才能调用getWidth()来获取。因此,getWidth()获取的宽度是在View设定好布局后整个View的宽度。

getMeasuredWidth()

/**
     * Like {@link #getMeasuredWidthAndState()}, but only returns the
     * raw width component (that is the result is masked by
     * {@link #MEASURED_SIZE_MASK}).
     *
     * @return The raw measured width of this view.
     */
    public final int getMeasuredWidth() {
        return mMeasuredWidth & MEASURED_SIZE_MASK;
    }

从源码上看,getMeasuredWidth()获取的是mMeasuredWidth的这个值。这个值是一个8位的十六进制的数字,高两位表示的是这个measure阶段的Mode的值,具体可以查看MeasureSpec的原理。这里mMeasuredWidth & MEASURED_SIZE_MASK表示的是测量阶段结束之后,View真实的值。而且这个值会在调用了setMeasuredDimensionRaw()函数之后会被设置。所以getMeasuredWidth()的值是measure阶段结束之后得到的View的原始的值。

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

    protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        boolean optical = isLayoutModeOptical(this);
        if (optical != isLayoutModeOptical(mParent)) {
            Insets insets = getOpticalInsets();
            int opticalWidth  = insets.left + insets.right;
            int opticalHeight = insets.top  + insets.bottom;

            measuredWidth  += optical ? opticalWidth  : -opticalWidth;
            measuredHeight += optical ? opticalHeight : -opticalHeight;
        }
        setMeasuredDimensionRaw(measuredWidth, measuredHeight);
    }

    private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
        mMeasuredWidth = measuredWidth;
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }

总结一下,getMeasuredWidth是measure阶段获得的View的原始宽度,getWidth是layout阶段完成后,其在父容器中所占的最终宽度

如何在onCreate中拿到View的宽度和高度?

在onCreate()中获取View的高宽有三种方法:

  1. View.post(runnable)
view.post(new Runnable() {
            @Override
            public void run() {
                int width = view.getWidth();
                int measuredWidth = view.getMeasuredWidth();
                Log.i(TAG, "width: " + width);
                Log.i(TAG, "measuredWidth: " + measuredWidth);
            }
        });

利用Handler通信机制,发送一个Runnable到MessageQueue中,当View布局处理完成时,自动发送消息,通知UI进程。借此机制,巧妙获取View的高宽属性,代码简洁,相比ViewTreeObserver监听处理,还不需要手动移除观察者监听事件。

  1. ViewTreeObserver.addOnGlobalLayoutListener()

监听View的onLayout()绘制过程,一旦layout触发变化,立即回调onLayoutChange方法。
注意,使用完也要主要调用removeOnGlobalListener()方法移除监听事件。避免后续每一次发生全局View变化均触发该事件,影响性能。

ViewTreeObserver vto = view.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                Log.i(TAG, "width: " + view.getWidth());
                Log.i(TAG, "height: " + view.getHeight());
            }
        });
  1. View.measure(int widthMeasureSpec, int heightMeasureSpec)

除了在onCreate()中获得View的高宽,还可以在Activity的onWindowFocusChanged() 方法中获得高宽。

目录
相关文章
|
6月前
|
索引
for in 和 for of的区别
for in 和 for of的区别
|
27天前
|
JavaScript 前端开发 索引
for in与for of的区别
for in与for of的区别
48 0
|
2月前
i++和++i的区别
i++和++i的区别
41 3
|
6月前
|
Web App开发 安全 应用服务中间件
浅谈C/S vs. B/S的区别
浅谈C/S vs. B/S的区别
186 0
|
JavaScript 小程序
bindtap和catchtap的区别?
在微信小程序中,bindtap 和 catchtap 都是用于绑定点击事件的属性,但它们在事件冒泡和事件捕获方面有所不同。
|
安全 C#
C#委托事件的区别
C#委托事件的区别
164 0
|
存储
逻辑移位与算术移位的区别
用一句简单的话来说就是:逻辑移位不需要考虑符号位,算术移位需要考虑符号位,我们都知道。数在计算机中都是以补码的形式来存储的,这才造成了逻辑移位和算术移位的的差别。
315 0
||、&&、!的使用与区别
||、&&、!的使用与区别
132 0
|
算法 IDE Unix
C和C++的区别
C和C++的区别
196 0
rsaCheckV2 和rsaCheckV1的区别分享
说明: 目前支付宝的SDK验签方法主要有两种一种是rsaCheckV1一种是rsaCheckV2 两种验签方法用于不同的接口的返回参数验签 1.rsaCheckV1验签方法   rsaCheckV1验签方法主要用于支付接口的返回参数的验签比如:当面付,APP支付,手机网站支付,电脑网站支付 这些接口都是使用rsaCheckV1方法验签的 2.
3595 11