普通View的MeasureSpec的创建规则

2021-09-30  本文已影响0人  雨来

可以先读的文章:
https://cloud.tencent.com/developer/article/1459335

我先借用两张图:

1、

image.png

2、

image.png

上面两张图的由来:(前面几个判断我是加了注释了)

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {

        //spc 传的是(自己onMeasure方法接收到 widthMeausreSpec 和 heightMeasureSpec) 这个方法是自己测量子view的时候用的

        //padding  这个参数则自己的 getPaddingLeft()和getPaddingRight()  childDimension 也是子view的 layoutParmars.width 或 layoutParmars.height

        int specMode = MeasureSpec.getMode(spec); //自己的模式
        int specSize = MeasureSpec.getSize(spec); //自己的尺寸(父亲给你的尺寸)  上有父(参考上)下有子(拿到子) 最后决定自己的高度

        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
            // Parent has imposed an exact size on us
            case MeasureSpec.EXACTLY:
                if (childDimension >= 0) {

                    //如果 自己的mode是 exactly 并且 子View的尺寸是一个确定的值 也就是exactly 那么 子view的尺寸就是自己的 childDimension (也就像 一个线性布局 设置固定高度为 100个dp 里面再有一个TextView高度设置成
                    // 固定高度为 30dp 那么这个 TextView的高度就是 30个dp)
                    resultSize = childDimension;

                    //如果 自己的mode 是exactly 并且子view的 尺寸是一个具体的值并且大于0 那么 子view的 mode 就是  MeasureSpec.EXACTLY     resultMode = MeasureSpec.EXACTLY;
                    resultMode = MeasureSpec.EXACTLY;
                } else if (childDimension == LayoutParams.MATCH_PARENT) {
                    //子view的的 尺寸  如果 父mode 是exactly(确切的值 如 100dp ) 那么子view的 尺寸LayoutParams.MATCH_PARENT 那么 子view的尺寸就是 size 子view的尺寸是父view给自己的自己的参考尺寸
                    // Child wants to be our size. So be it. (孩子想成为我们的尺寸 那么给它 自己有多大就给子view多大)
                    resultSize = size;
                    resultMode = MeasureSpec.EXACTLY;
                } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                    // Child wants to determine its own size. It can't be
                    // bigger than us.
                    resultSize = size;
                    resultMode = MeasureSpec.AT_MOST;
                }
                break;

            // Parent has imposed a maximum size on us
            case MeasureSpec.AT_MOST:
                if (childDimension >= 0) {
                    // Child wants a specific size... so be it
                    resultSize = childDimension;
                    resultMode = MeasureSpec.EXACTLY;
                } else if (childDimension == LayoutParams.MATCH_PARENT) {
                    // Child wants to be our size, but our size is not fixed.
                    // Constrain child to not be bigger than us.
                    resultSize = size;
                    resultMode = MeasureSpec.AT_MOST;
                } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                    // Child wants to determine its own size. It can't be
                    // bigger than us.
                    resultSize = size;
                    resultMode = MeasureSpec.AT_MOST;
                }
                break;

            // Parent asked to see how big we want to be
            case MeasureSpec.UNSPECIFIED:
                if (childDimension >= 0) {
                    // Child wants a specific size... let him have it
                    resultSize = childDimension;
                    resultMode = MeasureSpec.EXACTLY;
                } else if (childDimension == LayoutParams.MATCH_PARENT) {
                    // Child wants to be our size... find out how big it should
                    // be
                    resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                    resultMode = MeasureSpec.UNSPECIFIED;
                } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                    // Child wants to determine its own size.... find out how
                    // big it should be
                    resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                    resultMode = MeasureSpec.UNSPECIFIED;
                }
                break;
        }
        //noinspection ResourceType
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

通过上面的方法 我们应该明天上面两张图怎么看了
这三种模式(mode)是通过 父view给我们 也就是自身的mode


image.png

通过方法然后再看图的总结是(如何看图):
如果子view是固定大小具体数值 dp/px的话,如果自身的mode是 exactly 那么 那么子view 的mode和size就是下面标红的


image.png

这个图一定要学会看如果这个图都看不懂,更不要提说自己会自定义view了

最后的总结:

一个view的measureSpc 是由自身的layoutParams和父layout的measureSpec决定的

父layout的 measureSpec 是如何获取的呢
image.png

当前View获取父layout的measureSpec 只需要在当前View onMeasure() 方法里拿到 widthMeasureSpec
然后通过api MeasureSpec.getMode(widthMeasureSpec) 就可以获取了

非常不错的一篇博文:
https://www.jianshu.com/p/3b6d0c17cdb0

上一篇下一篇

猜你喜欢

热点阅读