分析View的onMeasure的底层实现

啥都不说,先上源代码


protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
 //这在官方的文档中有说明,让我们当重写这个方法时,必须调用,不然会报非法异常
}

底层调用了setMeasuredDimention传入默认的大小,参数为getSuggestedMinimunWidth()的返回值,那么getSuggestedMinimunWidth()做了什么,我们看看

protected int getSuggestedMinimumWidth() {
    return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
//这里的mBackground是Drawable对象
}

返回的背景图片的最小值与视图的最小值的最大值。
何以证明?
那么我们就查看一下mBackGround的由来。我查看了setBackgroundColor
setBackgroundResource的源代码,发现最终都是调用了setBackground。而setBackground又在底层调用了setBackgroundDrawable()方法
我就在这里找了一下,果不其然,被我发现了

if (mBackground == null
        || mBackground.getMinimumHeight() != background.getMinimumHeight()
        || mBackground.getMinimumWidth() != background.getMinimumWidth()) {
    requestLayout = true;
}

// Set mBackground before we set this as the callback and start making other
// background drawable state change calls. In particular, the setVisible call below
// can result in drawables attempting to start animations or otherwise invalidate,
// which requires the view set as the callback (us) to recognize the drawable as
// belonging to it as per verifyDrawable.
mBackground = background;
if (background.isStateful()) {
    background.setState(getDrawableState());
}
if (isAttachedToWindow()) {
    background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
}

上面明显有一个赋值过程,当然这都不是重点。有兴趣可以去看看。

那么返回来我们看看getDefaultSize()

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

我们发现当Measure.mode==UNSPECIFIED,也即是不限制子视图的大小的时候,getDefault将返回背景图片的最小值与视图的最小值的最大值。当然在一般情况下,就是MeasureSpec.getSize的大小。
进一步,我们里来到了setMeasuredDmention()并将解析到的数据传入。

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

我们发现在这里,这是对值进行了处理,

之后就传给了setMeasuredDimentionRaw(),那么在setMeasuredDimentionRaw又做了什么?,我们瞧瞧看。

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

    mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}

将值传递给了View的测量宽度。那么我们就要想,之前使用getMeasureWidth()和getMeasureHeight()是不是传递的就是这个值呢?
我们看看去.

public final int getMeasuredWidth() {
    return mMeasuredWidth & MEASURED_SIZE_MASK;
}

这是宽度的返回值。到这里你可能认为我真的去算!!!!!!我只能说你想多了
亏自己还是写程序的,自己测一下就是喽

    public void getAnd(){   
        int a=400;
        System.out.println(a&0x00ffffff);
    }

带了个值试了一下,结果还是原来的数据看来自己猜的是对的。

也就是说我们通过setMesureDimention(int,int)来设置的值就是我们通过getMeasureWidth()和getMeasureHeight(int,int)设置的值。

水平有限,如有错误,请指出

猜你喜欢

转载自blog.csdn.net/qq_37657081/article/details/79681942