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

- 父容器在
onMeasure中,会遍历调用子View的measure方法。 - 所有子View的
measure完成后,才会进入layout过程,其调用过程与measure类似。 layout过程完成后,最后进入draw过程,其过程与measure类似,不过performDraw的传递是在draw方法中通过dispatchDraw方法实现的。
- 父容器在
只有在Measure完成后,才能通过
getMeasureWidth和getMeasureHeight获取View测量后的宽高,它们在几乎所有的情况下等同于View的最终宽高,但特殊情况除外。- 同理,Layout完成后,才能拿到View的四个顶点的位置,并通过
getWidth和getHeight获取View的最终宽和高。
- 同理,Layout完成后,才能拿到View的四个顶点的位置,并通过
DecorView是顶级View。
- 一般情况下,它内部会包含一个竖直方向的线性布局,上面是标题栏,下面是内容区。
- 在Activity中
setContentView所设置的布局文件,实际上是被加到内容区。 - 内容区的id是可以获得的,其ID是
android.R.id.content,对第一个子View就是我们所设置的View。 - DecorView是一个
FramLayout,View层的所有事件都先经过DecorView,然后才逐级分发。
MeasureSpec
大致看看源码:
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_MOST:layout_width/layout_height指定为wrap_content,父容器将指定一个可用大小的SpecSize,View的大小不能大于这个值。具体的值要看不同View的具体实现。UNSPECIFIED:父容器不对View有任何限制。开发人员在绘制自定义View的时候会用到。
MeasureSpec和LayoutParams针对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有关。
普通View的
MeasureSpec的创建规则, 查看getChildMeasureSpec源码即可理解:父Spec View尺寸 View的SpecSize View的SpecMode EXACTLY固定值>=0 固定值 EXACTLYEXACTLYMATCH_PARENT父SpecSize-padding EXACTLYEXACTLYWRAP_CONTENT父SpecSize-padding AT_MOSTAT_MOST固定值>=0 固定值 EXACTLYAT_MOSTMATCH_PARENT父SpecSize-padding AT_MOSTAT_MOSTWRAP_CONTENT父SpecSize-padding AT_MOSTUNSPECIFIED固定值>=0 固定值 EXACTLYUNSPECIFIEDMATCH_PARENT0 UNSPECIFIEDUNSPECIFIEDWRAP_CONTENT0 UNSPECIFIED
View工作原理系列博客
View的工作原理(一):MeasureSpec
View的工作原理(二):measure
View的工作原理(三):layout与draw
View的工作原理(四):自定義View
本文详细介绍了Android中View的绘制流程,包括measure、layout和draw三个阶段。measure阶段测量View的宽高;layout阶段确定View的位置;draw阶段将View绘制到屏幕上。文章还深入探讨了MeasureSpec的作用及其实现机制。
839

被折叠的 条评论
为什么被折叠?



