5.3 RelativeLayout
5.3.1 介绍
RelativeLayout是android的5大常用布局之一,其使用方法和常用介绍这里不再赘述。
我们对RelativeLayout一般了解的是它是一个布局,这里从类的角度和view的角度来分析它。
RelativeLayout是一个类,所以有其构造过程,在布局文件被inflate的时候,会去创建这个类。
RelativeLayout extends ViewGroup,所以它是view的子类和实例,在RelativeLayout 类型的view的绘制流程中,实际会调用到RelativeLayout的方法。
除此之外,RelativeLayout并无其他特殊,其布局文件的属性也就类似我们调用一般类的方法设置成员变量一样。
Positions the bottom edge of this view above the given anchor view ID. | |
Positions the baseline of this view on the baseline of the given anchor view ID. | |
Makes the bottom edge of this view match the bottom edge of the given anchor view ID. | |
Makes the end edge of this view match the end edge of the given anchor view ID. | |
Makes the left edge of this view match the left edge of the given anchor view ID. | |
If true, makes the bottom edge of this view match the bottom edge of the parent. | |
If true, makes the end edge of this view match the end edge of the parent. | |
If true, makes the left edge of this view match the left edge of the parent. | |
If true, makes the right edge of this view match the right edge of the parent. | |
If true, makes the start edge of this view match the start edge of the parent. | |
If true, makes the top edge of this view match the top edge of the parent. | |
Makes the right edge of this view match the right edge of the given anchor view ID. | |
Makes the start edge of this view match the start edge of the given anchor view ID. | |
Makes the top edge of this view match the top edge of the given anchor view ID. | |
If set to true, the parent will be used as the anchor when the anchor cannot be be found for layout_toLeftOf, layout_toRightOf, etc. | |
Positions the top edge of this view below the given anchor view ID. | |
If true, centers this child horizontally within its parent. | |
If true, centers this child horizontally and vertically within its parent. | |
If true, centers this child vertically within its parent. | |
Positions the start edge of this view to the end of the given anchor view ID. | |
Positions the right edge of this view to the left of the given anchor view ID. | |
Positions the left edge of this view to the right of the given anchor view ID. | |
Positions the end edge of this view to the start of the given anchor view ID. |
5.3.2 绘制分析
RelativeLayout继承自ViewGroup,属于view控件,因此也遵从view的绘制逻辑。
根据我们对view的理解,其绘制大体也是按measure—layout—draw的流程处理的。
RelativeLayout的测量过程分如下几大步,
5.3.2.1.1子view的分组排序
调用sortChildren();,将子view排序上水平方向和垂直方向两个view列表:mSortedHorizontalChildren、mSortedVerticalChildren。
sortChildren | 将子view排序上水平方向和垂直方向两个view列表。 |
findRoots | 找出不依赖别的view的view,布局里view间的关系有自己独立的,有依赖于其他的view的。这个函数将view做成内存节点,并将view的属性读出来,设置他们相互的关系是否依赖和被依赖,并将不依赖的view做成一个列表返回。 |
getSortedViews | 将所有view按过滤规则排序,这里的过滤规则主要分两个大方向:水平和垂直。其排序思路如下,以水平为例(便于理解,我们自己定义被依赖者为“上级”,依赖其他view的为“下级”,一个上级有多个下级,一个下级也可以有多个上级,但上级是没有上级的,在排序到新view列表中时,同级view之间按扫描顺序添加到列表,下级view则添加到其最后一个上级之后),先是用findRoots找出一个水平方向独立不依赖的上级view列表,先将上级view逐个添加到排序列表,每添加一个上级view时,找到其下级view,将他们的关系从下级view里面删除,如果下级view由于这个原因变成独立不依赖的“假上级”view,则可以将它加入上级view列表,在下一个循环就被加入到排序列表,位于其以前的上级view之后;如果下级view有多个上级view,则会在上级view列表轮询的时候,加入到最后一个上级view之后,最终形成这样一个排序列表(上级a--下级a--上级b-下级b1-下级b2-下级ab-上级c--下级c--下级ac--下级abc,下标表示下级的依赖关系)。另需注意的是将可见不可见的view都排列起来的,因为可见不可见随时会改变,保持所有view的关系是必须的。 |
5.3.2.1.2坐标和属性初始
初步初始四个方向坐标,初始坐标模式,初始gravity。
传入的widthMeasureSpec是一个32位整数,是坐标模式和坐标值的组合数据,坐标模式占高2bit,含义如下:
/**
* Measure specification mode: The parent has not imposed any constraint
* on the child. It can be whatever size it wants.
*/
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.
*/
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.
*/
public static final int AT_MOST = 2 << MODE_SHIFT;
5.3.2.1.3水平方向
水平方向的子view测量是计算出所有view的水平方向的坐标值,调用3个函数,
applyHorizontalSizeRules | 根据view的可见性和相互关系,初步算出每个view的左右坐标。相互关系以被依赖者为锚点,根据getSortedViews,总有一个上级不依赖于其他view,只依赖于父view,作为基准锚点的。 |
measureChildHorizontal | 单个view的独立坐标测量 |
positionChildHorizontal | 精确计算出每个view左右坐标值 |
5.3.2.1.4垂直方向
垂直方向和水平方向处理逻辑类似。
但多一个步骤,就是根据wrapcontent和gravity初步计算relativeLayout的坐标。
5.3.2.1.5 RelativeLayout坐标计算
根据wrapcontent和gravity等属性值精确计算relativeLayout的坐标。
5.3.2.2 Layout过程
其layout过程就是遍历所有子view的layout
5.3.2.3 Draw过程
没有重载draw方法,就是直接使用了父类的draw方法。