本篇你将了解到:
- layout 方法的作用
- onLayout 方法是如何布局子 View 的
- 实战,如何快乐的自定义 View
在经过第一步的测量后,成功计算了每一个 View 的尺寸。但是要成功的把 View 绘制到屏幕上,只有 View 的尺寸还不行,还需要准确的知道该 View 应该被绘制到什么位置。
layout 方法
每一个 parent 会调用 children 的 layout
方法,来设置 children view 的位置。我们简要的给出 layout
的伪代码,去看看里面具体做了什么工作。
public void layout(int l, int t, int r, int b) {
if (根据一些flag,发现需要进一步measure) {
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
}
// 暂存旧的位置信息
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
// 设置新的位置信息
mLeft = l;
mTop = t;
mBottom = b;
mRight = r;
if (layout改变了 || 需要layout) {
onLayout(changed, l, t, r, b);
// 回调 layoutChange 事件
for (遍历监听对象) {
listener.onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
// 标记为已经执行过layout
}
根据以上伪代码可得知,layout
方法的工作主要为以下三点:
- 修改当前 view 的位置;
- 如果位置变化了的话,执行
onLayout
方法; - 调用所有监听器的
onLayoutChange
事件;
1,3 两点是很好理解的,那 2 中,onLayout
方法是用来做什么的呢?
onLayout 方法
每一个 ViewGroup
的子类,都需要求重写 onLayout
这个抽象方法,来确定子 View 在 ViewGroup
中的是如何布局的。
所以在上方 layout
方法中,代表着如果当前 View 的布局发生变化后,需要取重新布局一下所有的子 View。
我们根据几种熟悉的布局,如 LinearLayout
,RelativeLayout
的 onLayout
方法的源码,可以得出以下规律。
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (遍历子View) {
/**
根据如下数据计算。
1、自己当前布局规则。比如垂直排放或者水平排放。
2、子View的测量尺寸。
3、子View在所有子View中的位置。比如位置索引,第一个或者第二个等。
*/
child.layout(上面计算出来的位置信息);
}
}
实战:自定义View
我们需要达到以下效果:
- 每一个子 View 在竖直方向上线性分布;
- 每一个子 View 在水平方向,逐个向右偏移量增加 30dp;
- 使用 wrap_content 时,能达到刚刚好包裹住子 View;
- 使用 match_parent 时,充满父 View;
效果图
xml 文件格式
代码就不贴了,没有任何意义,想看的去我练舞房Github看:
- AViewGroup:Github 地址,是 kotlin 写的
- BView:Github 地址,这个是 Java