• 通过源码分析View的测量


    要理解View的测量,首先要了解MeasureSpec,系统在测量view的宽高时,要先确定MeasureSpec。

    MeasureSpec(32为int值)由两部分组成:

    SpecMode(高2位):测量模式。

    SpecSize(低30位):某种测量模式下的规格大小。

    SpecMode有3类:

    UNSPECIFIED: 父容器不对view做大小限制,一般用于系统内部,表示一种测量状态。

    EXACTLY:精确模式。对应于:LayoutPrams中的match_parent和具体数值。

    AT_MOST:最大值模式。对应于LayoutParam中的wrap_content模式。

    接下来我们看看View的onMeasure方法:

    /**
         * <p>
         * Measure the view and its content to determine the measured width and the
         * measured height. This method is invoked by {@link #measure(int, int)} and
         * should be overridden by subclasses to provide accurate and efficient
         * measurement of their contents.
         * </p>
         *
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                    getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
        }

    该方法是由measure来调用的,view宽高的测量值最终是通过setMeasuredDimension来设置,具体实现不去深究。


    我们看看getDefaultSize方法:

    /**
         * Utility to return a default size. Uses the supplied size if the
         * MeasureSpec imposed no constraints. Will get larger if allowed
         * by the MeasureSpec.
         *
         * @param size Default size for this view
         * @param measureSpec Constraints imposed by the parent
         * @return The size this view should be.
         */
        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;
        }

    先从MeasureSpec中获取的测量模式specMode和该模式下的大小specSize,然后对测量模式进行判断,如果是UNSPECIFIED,那么结果就是参数size,对于这个size是什么等会讨论。如果是AT_MOST和EXACTLY,那么结果就是view测量后的大小specSize。

    那么这个参数size到底是什么呢?它是由实参getSuggestedMinimumWidth()和getSuggestedMinimumHeight()传下来的,我们进去getSuggestedMinimumWidth()看看。

    /**
         * Returns the suggested minimum width that the view should use. This
         * returns the maximum of the view's minimum width)
         * and the background's minimum width
         *  ({@link android.graphics.drawable.Drawable#getMinimumWidth()}).
         * <p>
         * When being used in {@link #onMeasure(int, int)}, the caller should still
         * ensure the returned width is within the requirements of the parent.
         *
         * @return The suggested minimum width of the view.
         */
        protected int getSuggestedMinimumWidth() {
            return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
        }

    从代码我们可以看出如果该view设置了背景,那么就返回max(mMinWidth, mBackground.getMinimumWidth()),否则返回mMinWidth。
    mMinWidth是什么呢?它是对应android:minWidth这个属性的值,若是不指定,那么默认为0.

    max(mMinWidth, mBackground.getMinimumWidth()):返回mMinWidth和mBackground.getMinimumWidth()两者中的最大值。

    mBackground.getMinimumWidth()的代码如下:

    /**
         * Returns the minimum width suggested by this Drawable. If a View uses this
         * Drawable as a background, it is suggested that the View use at least this
         * value for its width. (There will be some scenarios where this will not be
         * possible.) This value should INCLUDE any padding.
         *
         * @return The minimum width suggested by this Drawable. If this Drawable
         *         doesn't have a suggested minimum width, 0 is returned.
         */
        public int getMinimumWidth() {
            final int intrinsicWidth = getIntrinsicWidth();
            return intrinsicWidth > 0 ? intrinsicWidth : 0;
        }


    它返回的是Drawable的原始宽度,如果Drawable有原始宽度的话。否则返回0.

    因此若view有设置背景,那么size就是android:minWidth和背景最小宽度这两者的最大值,若没有设置背景,那么size的值就是android:minWidth的值。

  • 相关阅读:
    【Android】12.0 UI开发(三)——列表控件ListView的简单实现2
    【Android】11.0 UI开发(二)——列表控件ListView的简单实现1
    【Android】10.0 UI开发——如何编写程序界面、常见控件的使用
    【转载】从创业者角度看《印度合伙人 Padman》后的一点感受
    【代码笔记】Java常识性基础补充(二)——数组、ArrayList集合、ASCII编码、 eclipse基础操作、eclipse调试、eclipse项目导入、eclipse快捷键
    Android 实现高斯模糊效果和圆角图片
    Android 获取当前系统时间
    Android RecycleView悬浮按钮点击返回顶部
    eclipse连接mysql
    mysql的增删改查语句
  • 原文地址:https://www.cnblogs.com/tangZH/p/7029372.html
Copyright © 2020-2023  润新知