什么是viewmodel_体系包括什么

什么是viewmodel_体系包括什么MeasureSpec是View的内部类,MeasureSpec 封装了从父级传递到子级的测量要求。每个 MeasureSpec 代表对宽度或高度的要求。

View体系(七)理解

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

MeasureSpecView的内部类,MeasureSpec 封装了从父级传递到子级的测量要求。每个 MeasureSpec 代表对宽度或高度的要求。 MeasureSpec 由大小和模式两部分组成。

更详细的说明请看 Google官方文档

下面是MeasureSpec的源码:(基于Android 12

    public static class MeasureSpec {
        private static final int MODE_SHIFT = 30;
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;

        public static final int UNSPECIFIED = 0 << MODE_SHIFT;

        public static final int EXACTLY     = 1 << MODE_SHIFT;

        public static final int AT_MOST     = 2 << MODE_SHIFT;

        public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode) {
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode & MODE_MASK);
            }
        }

        public static int makeSafeMeasureSpec(int size, int mode) {
            if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
                return 0;
            }
            return makeMeasureSpec(size, mode);
        }

        public static int getMode(int measureSpec) {
            return (measureSpec & MODE_MASK);
        }

        public static int getSize(int measureSpec) {
            return (measureSpec & ~MODE_MASK);
        }

        static int adjust(int measureSpec, int delta) {
            final int mode = getMode(measureSpec);
            int size = getSize(measureSpec);
            if (mode == UNSPECIFIED) {
                return makeMeasureSpec(size, UNSPECIFIED);
            }
            size += delta;
            if (size < 0) {
                Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
                        ") spec: " + toString(measureSpec) + " delta: " + delta);
                size = 0;
            }
            return makeMeasureSpec(size, mode);
        }

        public static String toString(int measureSpec) {
            int mode = getMode(measureSpec);
            int size = getSize(measureSpec);

            StringBuilder sb = new StringBuilder("MeasureSpec: ");

            if (mode == UNSPECIFIED)
                sb.append("UNSPECIFIED ");
            else if (mode == EXACTLY)
                sb.append("EXACTLY ");
            else if (mode == AT_MOST)
                sb.append("AT_MOST ");
            else
                sb.append(mode).append(" ");

            sb.append(size);
            return sb.toString();
        }
    }

从源码可以看出,它代表了32位int值,其中高2位代表mode,低30位代表sizemode指测量模式,size指测量值。mode有3种模式:

  • UNSPECIFIED:未指定模式,父View没有对子View施加任何限制。它可以是任何它想要的大小。

  • EXACTLY:精确模式,父View已经确定了子View的确切尺寸。无论子View想要多大,都将获得这些界限。

  • AT_MOST:最大模式,子View可以根据需要达到指定的最大的大小。

makeMeasureSpec用来保存宽和高的信息,getMode用来获取测量模式,getSize用来获取测量大小。

MeasureSpec受自身LayoutParams和父ViewMeasureSpec共同影响。作为顶层ViewDecorView来说,其并没有父View,那它的MeasureSpec是如何得来的呢?我们回到ViewRootImplperformTraversals方法:


                if (!mStopped || wasReportNextDraw) {
                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
                        || mHeight != host.getMeasuredHeight() || dispatchApplyInsets ||
                        updatedConfiguration) {
                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);//1
                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

                    if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
                            + mWidth + " measuredWidth=" + host.getMeasuredWidth()
                            + " mHeight=" + mHeight
                            + " measuredHeight=" + host.getMeasuredHeight()
                            + " dispatchApplyInsets=" + dispatchApplyInsets);

                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);//2

再看注释1处的getRootMeasureSpec方法:

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

        case ViewGroup.LayoutParams.MATCH_PARENT:
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
        }
        return measureSpec;
    }

第一个参数windowSize指窗口的尺寸,所以对于DecorView来说,它的MeasureSpec由自身的LayoutParams和窗口的尺寸决定,这一点和普通的View是不同的。 再回到上面看注释2处的performMeasure方法:

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        if (mView == null) {
            return;
        }
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);//1
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

注释1处调用了mView.measure方法,进入了viewmeasure流程。

学习更多知识,请关注我的个人博客:droidYu

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13898.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注