本篇你將了解到:
- layout 方法的作用
- onLayout 方法是如何布局子 View 的
- 實戰(zhàn),如何快樂的自定義 View
在經(jīng)過第一步的測量后,成功計算了每一個 View 的尺寸。但是要成功的把 View 繪制到屏幕上,只有 View 的尺寸還不行,還需要準(zhǔn)確的知道該 View 應(yīng)該被繪制到什么位置。
layout 方法
每一個 parent 會調(diào)用 children 的 layout 方法,來設(shè)置 children view 的位置。我們簡要的給出 layout 的偽代碼,去看看里面具體做了什么工作。
public void layout(int l, int t, int r, int b) {
if (根據(jù)一些flag,發(fā)現(xiàn)需要進一步measure) {
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
}
// 暫存舊的位置信息
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
// 設(shè)置新的位置信息
mLeft = l;
mTop = t;
mBottom = b;
mRight = r;
if (layout改變了 || 需要layout) {
onLayout(changed, l, t, r, b);
// 回調(diào) layoutChange 事件
for (遍歷監(jiān)聽對象) {
listener.onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
// 標(biāo)記為已經(jīng)執(zhí)行過layout
}
根據(jù)以上偽代碼可得知,layout 方法的工作主要為以下三點:
- 修改當(dāng)前 view 的位置;
- 如果位置變化了的話,執(zhí)行
onLayout方法; - 調(diào)用所有監(jiān)聽器的
onLayoutChange事件;
1,3 兩點是很好理解的,那 2 中,onLayout 方法是用來做什么的呢?
onLayout 方法
每一個 ViewGroup 的子類,都需要求重寫 onLayout 這個抽象方法,來確定子 View 在 ViewGroup 中的是如何布局的。
所以在上方 layout 方法中,代表著如果當(dāng)前 View 的布局發(fā)生變化后,需要取重新布局一下所有的子 View。
我們根據(jù)幾種熟悉的布局,如 LinearLayout,RelativeLayout 的 onLayout 方法的源碼,可以得出以下規(guī)律。
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (遍歷子View) {
/**
根據(jù)如下數(shù)據(jù)計算。
1、自己當(dāng)前布局規(guī)則。比如垂直排放或者水平排放。
2、子View的測量尺寸。
3、子View在所有子View中的位置。比如位置索引,第一個或者第二個等。
*/
child.layout(上面計算出來的位置信息);
}
}
實戰(zhàn):自定義View
我們需要達(dá)到以下效果:
- 每一個子 View 在豎直方向上線性分布;
- 每一個子 View 在水平方向,逐個向右偏移量增加 30dp;
- 使用 wrap_content 時,能達(dá)到剛剛好包裹住子 View;
- 使用 match_parent 時,充滿父 View;

效果圖
xml 文件格式
<com.lijing.dev.todo.view.AViewGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.lijing.dev.todo.view.BView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/res_yellow" />
<com.lijing.dev.todo.view.BView
android:layout_width="80dp"
android:layout_height="60dp"
android:background="#8BC34A" />
<com.lijing.dev.todo.view.BView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#E91E63" />
</com.lijing.dev.todo.view.AViewGroup>
代碼就不貼了,沒有任何意義,想看的去我練舞房Github看:
- AViewGroup:Github 地址,是 kotlin 寫的
- BView:Github 地址,這個是 Java