问题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的宽。