View的Layout过程的作用是计算View的位置,即Left,top,right和bottom四个顶点的位置。
1.View的Layout过程
代码
public void layout(int l, int t, int r, int b) {
...
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
}
...
}
调用setFrame()方法,将传入的四个位置值,设为View的四个顶点的位置,代码如下。setOptialFrame()方法中实际上也是调用了setFrame()。
protected boolean setFrame(int left, int top, int right, int bottom) {
...
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
}
View的onLayout()方法是个空实现,因为这个方法的作用是计算子View在父ViewGroup中的位置,而在View中是没有子View的。
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
流程图
layout() -> setOpticalFrame()/setFrame() -> onLayout()
2.ViewGroup的Layout过程
代码
public void layout(int l, int t, int r, int b) {
...
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
}
...
}
流程与View的layout()过程相同,但ViewGroup的onLayout()方法是个抽象类,即自定义ViewGroup必须实现onLayout()方法!
重写的onLayout()方法一般有以下的代码步骤:
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// 1. 遍历所有子View
for (int i=0; i<getChildCount(); i++) {
View child = getChildAt(i);
// 2. 计算当前子View的四个位置值,也是自定义ViewGroup的关键
// 3. 根据上述4个位置的计算值,传递给子View的layout()方法,接下来的流程即是View的layout过程
child.layout(mLeft, mTop, mRight, mBottom);
}
}
}
流程图
layout() -> setOpticalFrame()/setFrame() -> onLayout() -> child.layout()
layout()方法的的发起
ViewRootImpl -> performTraversals() ->performLayout -> layout(),这里的host代表的是顶层View即DecorView。
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
...
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
...
}