View的工作原理(一):MeasureSpec

measure基本流程

  1. View的绘制流程是从ViewRootperformTraversals方法开始的。它经过measure、layout和draw三个过程才能最终将一个View绘制出来。
    • measure:测量View的宽和高
    • layout:确定View在父容器的位置
    • draw:将View绘制在屏幕上。
  2. performTraversals的工作流程:
    image

    1. 父容器在onMeasure中,会遍历调用子View的measure方法。
    2. 所有子View的measure完成后,才会进入layout过程,其调用过程与measure类似。
    3. layout过程完成后,最后进入draw过程,其过程与measure类似,不过performDraw的传递是在draw方法中通过dispatchDraw方法实现的。
  3. 只有在Measure完成后,才能通过getMeasureWidthgetMeasureHeight获取View测量后的宽高,它们在几乎所有的情况下等同于View的最终宽高,但特殊情况除外。

    • 同理,Layout完成后,才能拿到View的四个顶点的位置,并通过getWidthgetHeight获取View的最终宽和高。
  4. DecorView是顶级View。

    • 一般情况下,它内部会包含一个竖直方向的线性布局,上面是标题栏,下面是内容区。
    • 在Activity中setContentView 所设置的布局文件,实际上是被加到内容区。
    • 内容区的id是可以获得的,其ID是android.R.id.content,对第一个子View就是我们所设置的View。
    • DecorView是一个FramLayout,View层的所有事件都先经过DecorView,然后才逐级分发。

MeasureSpec

  1. 大致看看源码:

    public static class MeasureSpec {
        /** @hide */
        @IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
        @Retention(RetentionPolicy.SOURCE)
        public @interface MeasureSpecMode {}
    
        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 << View.MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode) {
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode & MODE_MASK);
            }
        }
    }
    @MeasureSpecMode
    public static int getMode(int measureSpec) {
        //noinspection ResourceType
        return (measureSpec & MODE_MASK);
    }
    
    public static int getSize(int measureSpec) {
        return (measureSpec & ~MODE_MASK);
    }

    Android源码中大量使用了位运算,比如Intent的各种FLAG。它们拥有更高的效率和更低的内存开销。

    SpecMode有三类:

    • EXACTLY: layout_width/layout_height指定为具体数值或match_parent,父容器就会指定一个精确的SpecSize。
    • AT_MOSTlayout_width/layout_height指定为wrap_content,父容器将指定一个可用大小的SpecSize,View的大小不能大于这个值。具体的值要看不同View的具体实现。
    • UNSPECIFIED:父容器不对View有任何限制。开发人员在绘制自定义View的时候会用到。
  2. MeasureSpecLayoutParams

    • 针对DecorView,其MeasureSpec由窗口的尺寸和其自身LayoutParams共同决定。

      • LayoutParams.MATCH_PARENT: Window can’t resize. Froce root view to be windowSize. EXACTLY模式,(强制)大小就是窗口的大小。
      • LayoutParams.WRAP_CONTENT: Window can resize. Set max size for root view. AT_MOST模式,将为root view设置最大尺寸,但不能超过窗口大小。
      • 固定大小(比如具体dp值): Window wants to be an exact size.Force root view to be that size. EXACTLY模式,(强制)root view尺寸就是指定的大小。
    • 而普通的View,则是由父容器的MeasureSpec和自身LayoutParams共同决定,此外还与父容器的pading和自身的margin有关。

  3. 普通View的MeasureSpec的创建规则, 查看getChildMeasureSpec源码即可理解:

    父SpecView尺寸View的SpecSizeView的SpecMode
    EXACTLY固定值>=0固定值EXACTLY
    EXACTLYMATCH_PARENT父SpecSize-paddingEXACTLY
    EXACTLYWRAP_CONTENT父SpecSize-paddingAT_MOST
    AT_MOST固定值>=0固定值EXACTLY
    AT_MOSTMATCH_PARENT父SpecSize-paddingAT_MOST
    AT_MOSTWRAP_CONTENT父SpecSize-paddingAT_MOST
    UNSPECIFIED固定值>=0固定值EXACTLY
    UNSPECIFIEDMATCH_PARENT0UNSPECIFIED
    UNSPECIFIEDWRAP_CONTENT0UNSPECIFIED

View工作原理系列博客

View的工作原理(一):MeasureSpec
View的工作原理(二):measure
View的工作原理(三):layout与draw
View的工作原理(四):自定義View

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android View的底层代码比较复杂,涉及到很多细节和设计模式。下面是一些View底层代码的简单解释: 1. View类:View是Android中所有UI控件的基类,它定义了一些基本的方法和属性,如onMeasure()、onLayout()和onDraw()等。 2. ViewGroup类:ViewGroup是所有布局容器的基类,它继承自View类,并且可以包含其他的ViewViewGroup。ViewGroup定义了一些方法和属性,用于管理和布局它所包含的子View。 3. MeasureSpec类:MeasureSpec是一个辅助类,用于计算View的尺寸。MeasureSpec包括三个属性:mode、size和UNSPECIFIED,用于描述View的测量模式以及宽高尺寸。 4. LayoutParams类:LayoutParams是一个布局参数类,用于描述View在布局容器中的位置和大小。每个布局容器都有自己的LayoutParams子类,如LinearLayout.LayoutParams和RelativeLayout.LayoutParams。 5. Canvas类:Canvas是一个画布类,它封装了绘制图形的方法和属性。在View的onDraw()方法中,可以通过Canvas来进行绘制操作。 6. Paint类:Paint是一个画笔类,用于设置绘制的颜色、样式等属性。 7. Drawable类:Drawable是一个可绘制的对象,它可以是一张图片、一个形状等。在View的onDraw()方法中,可以使用Drawable来表示绘制对象。 以上是View底层代码的一些简单解释,View底层代码的实现涉及到很多细节和设计模式,需要深入了解Android的UI系统和Java编程语言。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值