Android自定义控件之onLayout详解

    上一篇我们分析了onMeasure的具体调用流程,这里我们接着分析自定义控件的另一个方法:onlayout,onLayout的目的是确定子View在父View中的位置,因此我们的分析还是从ViewGroup的代表Linealayout为入口分析整个过程。

一.源码分析

    Linealayout的onLayout方法如下:
Android自定义控件之onLayout详解
还是同样的分了两个方向,我们用垂直方向来做代表进行分析,由于代码过长我们就分段分析:
Android自定义控件之onLayout详解
     整个过程都在计算ChildView的左上的坐标,先确定有子View的数量然后根据Gravity来确定第一个控件左上坐标的初始值,这里我们先说明一下View是如何确定位置的,借用一个大佬的图:
Android自定义控件之onLayout详解
    从上图可以看出控件的位置是通过左上和右下两个坐标来确定的,坐标的原点在左上角,正坐标方向为向右和向下,接着我们再看后面的代码:
Android自定义控件之onLayout详解Android自定义控件之onLayout详解
    这里遍历了子View然后单个进行计算,计算过程先利用getMeasureWidth/Height()来获得View的宽高,这里后续还会讲到为什么用这个方法。接着就是结合Gravity来计算childLeft和childTop,然后调用setChildFrame,传入左上角坐标和宽高,最后由于我们是分析垂直方向,因此最后要叠加childTop。接下来我们接着进入setChildFrameAndroid自定义控件之onLayout详解Android自定义控件之onLayout详解
Android自定义控件之onLayout详解
    这里的方式onMeasure的实现方法一直,这里调用了子View的layout方法,再调用onLyout方法,而且在onLyout方法中没有任何实现,也就是说实际上ViewGroup是依靠onlayout方法来确定子View所处位置,而View则依靠layout方法来决定自身位置。

二.getMeasureWidth()和getWidth()区别  

         在自定义View时很多新手会使用getWidth()方法来获取宽度,然后返回的都是0,这里我们具体分析一下两个方法的区别,便于理解。

    1.getMeasureWidth()

Android自定义控件之onLayout详解

        这里有两个参数,后者是个常量,我们就看前者什么时候开始赋值:

Android自定义控件之onLayout详解

查看该方法调用:

Android自定义控件之onLayout详解

    这里分两条路,我们就兵分两路去看:

(1)第一条:

Android自定义控件之onLayout详解

    第一条回到了measure方法中,这里先不做分析,我们再看第二条。

(2)第二条:

Android自定义控件之onLayout详解

    Android自定义控件之onLayout详解

Android自定义控件之onLayout详解

    这里看到最终还是回到了measure方法中,面的最后一张图实际上就是我们分析的两条路,因此getMeasureWidth方法有值返回时在onMeasure以后。

    2.getWidth()

   Android自定义控件之onLayout详解

这里有两个值,看什么时候初始化:

Android自定义控件之onLayout详解

Android自定义控件之onLayout详解

    从这里能看到最终是在View的layout方法中调用并初始化的,这里也是分了两条,从下图也能看出,前者方法实际上也是调用setFrame方法,因此最终还是在layout方法中才能初始化。

Android自定义控件之onLayout详解

    综合上面分析我们得出结论,getMeasureWidth()在ViewGroup调用onMeasure以后就能获得值,而getWidth()要在View调用layout方法以后,所以为什么自定义VeiwGroup的onLayout方法只能调用getMeasureWidth()。

    本篇文章我们分析了onLayout的具体实现过程,总体来说onLayout的实现思路和onMeasure是一致的,就是ViewGroup先计算,然后调用View的方法,最终确定View的最终位置。