View框架的工作流程为:测量每个View大小(measure)-->把每个View放置到相应的位置(layout)-->绘制每个View(draw)。
源代码分析
在View的源代码中,提取到了下面一些关于layout过程的信息。
我们知道,整棵View树的根节点是DecorView,它是一个FrameLayout,所以它是一个ViewGroup,所以整棵View树的测量是从一个ViewGroup对象的layout方法开始的。
View:
1、layout
//分配一个位置信息到一个View上面,每个parent会调用children的layout方法来设置children的位置。最好不要覆写该方法,有children的viewGroup,应该覆写onLayout方法
public void layout(int l, int t, int r, int b) ;
2、onLayout
/** 根据布局规则,计算每一个子View的位置,View类默认是空实现。 所以这里没有源代码*/
protected void onLayout(boolean changed, int left, int top, int right, int bottom);
ViewGroup:
ViewGroup中,只需要覆写onLayout方法,来计算出每一个子View的位置,并且把layout流程传递给子View。源代码:
ViewGroup没有实现,具体可以参考LinearLayout和RelativeLayout的onLayout方法。虽然各个具体实现都很复杂,但是基本流程是一样的,可以参考下面的伪代码。
protected void onLayout(boolean changed, int l, int t, int r, int b) { for (遍历子View) { /** 根据如下数据计算。 1、自己当前布局规则。比如垂直排放或者水平排放。 2、子View的测量尺寸。 3、子View在所有子View中的位置。比如位置索引,第一个或者第二个等。 */ 计算每一个子View的位置信息; child.layout(上面计算出来的位置信息); } }
结论
一般来说,自定义View,如果该View不包含子View,类似于TextView这种的,是不需要覆写onLayout方法的。而含有子View的,比如LinearLayout这种,就需要根据自己的布局规则,来计算每一个子View的位置。