MeasureSpec

1. MeasureSpec分析


1>:MeasureSpec = specSize + specMode,specSize表示大小,specMode表示规格,规格有3种:
第一:EXACTLY = 固定值(100dp)、match_parent 、fill_parent
第二:AT_MOST:wrap_content
第三:UNSPECIFIED:系统的,一般不用
2>:widthMeasureSpec 和 heightMeasureSpec这两个值,一般是 父view 计算好后传递给 子view,对于最外层根view的 这两个值,通过 performTraversals中的 getRootMeasureSpec可知:

private void performTraversals() {
    // 从根布局获取 widthMeasureSpec 和 heightMeasureSpec 的值
    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
}

   private static int getRootMeasureSpec(int windowSize, int rootDimension) {
        int measureSpec;
        switch (rootDimension) {

        case ViewGroup.LayoutParams.MATCH_PARENT:
            // 用 MeasureSpec.makeMeasureSpec组装 MeasureSpec 
            // rootDimension = MATCH_PARENT,specMode就为 EXACTLY
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            // rootDimension = WRAP_CONTENT,specMode就为 AT_MOST
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
        }
        return measureSpec;
    }

由上边可知:
在 getRootMeasureSpec方法中,用 MeasureSpec.makeMeasureSpec方法组装 MeasureSpec:
1>:当 rootDimension = MATCH_PARENT,specMode = EXACTLY;
2>:当 rootDimension = WRAP_CONTENT,specMode = AT_MOST;
并且 MATCH_PARENT和WRAP_CONTENT时候的 specSize都是 windowSize,表示 最外层的根view 都是 充满全屏;

2. 自定义MyView,继承View


/**
 * ================================================
 * Email: [email protected]
 * Created by Novate 2018/12/25 16:33
 * Version 1.0
 * Params:
 * Description:    自定义MyView,继承View
 * ================================================
*/

public class MyView extends View {

    // ... 省略代码
    /**
     * 这里只是模拟 onMeasure方法:
     *      不管在 activity_myview 布局文件中的宽高设置多少,最终的大小都是200*200;
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(200,200);
    }
}

效果图如下:


图片.png

首先调用setMeasuredDimension,然后调用 getMeasuredWidth和getMeasuredHeight 可以获取到子view 测量后的宽高;
如果直接调用 getMeasuredWidth和getMeasuredHeight ,那么这两个方法的值为0;

3. 自定义 TextView 的 onMeasure测量


比如 activity_main 布局是:LinearLayout中包裹了 3个 TextView

public class TextView extends View {
    public TextView(Context context) {
        this(context, null);
    }

    public TextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // specMode 测量模式如下
        // AT_MOST = wrap_content 
        // EXACTLY = 固定值100dp、match_parent 、fill_parent 

        // 模式和大小是由父布局和自己决定的  这里所说的父布局和自己指的就是
        // activity_main 中的 LinearLayout 和 TextView
        //比如说:父布局是包裹内容,就算子布局是match_parent,这个时候计算出的模式还是 AT_MOST
        //比如说:父布局是match_parent,子布局是match_parent,这个时候计算出的测量模式是 Exactly

//        setMeasuredDimension(widthMeasureSpec , heightMeasureSpec);
    }
}

你可能感兴趣的:(MeasureSpec)