对getWidth()/getHeight() 与 getMeasuredWidth()/getMeasuredHeight() 方法的理解

问题1:getWidth() & getMeasuredWidth() 方法返回的值是什么?
问题2: getWidth() & getMeasuredWidth() 方法分别什么时候调用?

这些方法都是在View类中的,首先看各自的源码:

int mMeasuredWidth;//mMeasuredWidth是View类中的全局变量
...
public final int getMeasuredWidth() {
        return mMeasuredWidth & MEASURED_SIZE_MASK;
    }

从上面的代码可以看出来,想要理解 getMeasuredWidth() 方法就需要理解 mMeasuredWidth 这个变量,那么这个变量是哪来的呢?出处如下:

private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
		//可以看到mMeasuredWidth 在此赋值
        mMeasuredWidth = measuredWidth;
        
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }

setMeasuredDimensionRaw() 方法同样是View类中的,这个方法何时被调用呢? 如下:

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);
    }

可以看到,setMeasuredDimension() 方法中调用了setMeasuredDimensionRaw() 方法。而setMeasuredDimension() 就很熟悉了,来源如下:

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

setMeasuredDimension() 是在 onMeasure() 方法中调用,用于保存View 宽高的测量值。

总结: getMeasuredWidth() 方法用于获取View 宽的测量值,View宽的测量值在 setMeasuredDimension() 方法中被赋值。

protected int mLeft;
protected int mRight;//mLeft,mRight是定义在View类中的全局变量
...
public final int getWidth() {
        return mRight - mLeft;
    }

分析同上, mRight,mLeft 是哪里被赋值的呢?如下:

protected boolean setFrame(int left, int top, int right, int bottom) {
  ...省略部分代码
            
            mLeft = left;
            mTop = top;
            mRight = right;
            mBottom = bottom;

...省略部分代码
           
    }

可以看到 mRight,mLeft 变量是在 setFrame() 方法中赋值的,那么 setFrame() 方法是在哪里被调用的呢?如下:

public void layout(int l, int t, int r, int b) {
...省略部分代码

        boolean changed = isLayoutModeOptical(mParent) ?
                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
                
...省略部分代码

}

可以看到 setFrame() 方法在 layout() 方法中被调用。

总结: getWidth() 用于获取View最终的宽,可以在 onLayout() 方法中调用 getWidth() 用以获取当前View/ViewGroup的宽。但是如果是在ViewGroup的 onLayout() 方法中,想要获取子View的宽必须调用子View的getMeasuredWidth() 方法。因为子View只有在调用了 layout() 方法之后才会为mLeft,mRight赋值,才能调用 getWidth() 获取View的宽。

解答1: getWidth() 返回View最终的宽,getMeasuredWidth()返回View宽的测量值,大部分情况下这两个值相等。只有重写了View的 layout() 方法才能使这两个值不相等。
解答2: getWidth() 方法可以在 setFrame() 方法之后调用( setFrame() 在layout()中被调用),比如onLayout() 里面,用于获取当前View/ViewGroup的宽。getMeasuredWidth() 可以在 setMeasuredDimension() 之后调用 (setMeasuredDimension() 在onMeasure() 中被调用),一般用于在onLayout() 获取子View的宽。

参考文章 https://www.jianshu.com/p/158736a2549d

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值