UI绘制流程(measure,layout,draw)

ViewRootImpl--

一、Measure (performMeasure)

1.measureSpace

ViewRootImpl--getRootMeasureSpec(),返回了一个int类型的measureSpace(以下简称ms),ms是个32位的int数值,他的前2位表示mode,后30位表示尺寸。

例:
    00      000000000000000000000000000000
specMode ↑  specSize

SpecMode分为3种EXACTLY、AT_MOST、UNSPECIFIED


        /**
         * Measure specification mode: The parent has not imposed any constraint
         * on the child. It can be whatever size it wants.
         */
        00000000000000000000000000000000
        1.父容器不对view做任何限制,系统内部使用
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;

        /**
         * Measure specification mode: The parent has determined an exact size
         * for the child. The child is going to be given those bounds regardless
         * of how big it wants to be.
         */
        01000000000000000000000000000000
        2.父容器检测出view的大小,view的大小就是SpecSize 
        子控件的LayoutParams的match_parent 以及 固定大小
        public static final int EXACTLY     = 1 << MODE_SHIFT;

        /**
         * Measure specification mode: The child can be as large as it wants up
         * to the specified size.
         */
        10000000000000000000000000000000
        3.父容器指定一个指定大小,view大小不能超过这个值, LayoutParams wrap_content
        public static final int AT_MOST     = 2 << MODE_SHIFT;
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
        int measureSpec;
        switch (rootDimension) {

        case ViewGroup.LayoutParams.MATCH_PARENT:
            // Window can't resize. Force root view to be windowSize.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            // Window can resize. Set max size for root view.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            // Window wants to be an exact size. Force root view to be that size.
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
        }
        return measureSpec;
    }

通过View--makeMeasureSpec()我们可以知道,
mode + size = MeasureSpec

        private static final int MODE_SHIFT = 30;
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;
/**
         * Creates a measure specification based on the supplied size and mode.
         *
         * The mode must always be one of the following:
         * 
    *
  • {@link android.view.View.MeasureSpec#UNSPECIFIED}
  • *
  • {@link android.view.View.MeasureSpec#EXACTLY}
  • *
  • {@link android.view.View.MeasureSpec#AT_MOST}
  • *
* *

Note: On API level 17 and lower, makeMeasureSpec's * implementation was such that the order of arguments did not matter * and overflow in either value could impact the resulting MeasureSpec. * {@link android.widget.RelativeLayout} was affected by this bug. * Apps targeting API levels greater than 17 will get the fixed, more strict * behavior.

* * @param size the size of the measure specification * @param mode the mode of the measure specification * @return the measure specification based on size and mode */ 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); } }

通过对MODE_MASK和~MODE_MASK 取 & 操作,取得mode 和 size

 MODE_MASK = 11000000000000000000000000000000
~MODE_MASK = 00111111111111111111111111111111
View的测量:
一、确定DecorViewde的MesasureSpec

DecorView的MesaureSpec有窗口大小和自身LayoutParams决定,遵循如下规则:
1.LayoutParams.MATCH_PARENT:精确模式,窗口大小
2.LayoutParams.WRAP_CONTENT:最大模式,最大为窗口大小
3.固定模式:精确模式,大小为LayoutParams大小

二、确定View的MeasureSpec
UI绘制流程(measure,layout,draw)_第1张图片
image.png

measure--onMeasure--setMeasureDimension--setMeasureDimensionRaw

ViewGroup的测量:

measure--onMeasure(测量子控件宽高)--setMeasureDimension--setMeasureDimensionRaw(保存自己的宽高)

二、Layout (performLayout)

1.View类型:
调用viwe.layout确定自身位置,即确定mLeft, mTop, mRight, mBottom
2.ViewGroup类型:
layout(来确定自己位置,4个点的位置)--onLauout(进行子view的布局)

三、Draw ( performDraw )

1.绘制背景 drawBackground(canvas)
2.绘制自己 onDraw(canvas)
3.绘制子View dispatchDraw(canvas) (view不会有)
4.绘制前景,如滚动条等装饰 onDrawForefround(canvas)

总结

onMeasure---onLayout---onDraw
当我们自定义的是容器的时候,需要去实现onLayout方法,自定义view的时候,可以不用重写它。
onDraw方法,可选,如果onDraw中放的都是系统控件,可以不用重写。

你可能感兴趣的:(UI绘制流程(measure,layout,draw))