系列文章目录
文章目录
前言
接上文,测量完View树的每个节点View的宽和高后,开始布局。
一、ViewRootImpl 的调用栈
ViewRootImpl->performLayout(lp, mWidth, mHeight);
host.layout()
ViewGroup -> layout(int l, int t, int r, int b)
View -> layout(int l, int t, int r, int b)
View ->setFrame(l, t, r, b)
onLayout(changed, l, t, r, b)
DecorView-> onLayout(changed, l, t, r, b)
FrameLayout->onLayout()
layoutChildren()
二、布局每个View
View.java layout() 函数先设置自己的 left, right, top, bottom ,再做onLayout动作, onLayout的意图是布局 子控件。 view 已经没有子控件了, 所以 view的onLayout 什么也不做。
protected int mLeft;
protected int mRight;
protected int mTop;
protected int mBottom;
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);
}
}
protected boolean setFrame(int left, int top, int right, int bottom) {
...
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
...
}
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
由于 ViewGroup 的 onLayout 是虚函数, 所以 ViewGroup 需要实现自己的onLayout
public final void layout(int l, int t, int r, int b) {
if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
if (mTransition != null) {
mTransition.layoutChange(this);
}
super.layout(l, t, r, b);
} else {
// record the fact that we noop'd it; request layout when transition finishes
mLayoutCalledWhileSuppressed = true;
}
}
protected abstract void onLayout(boolean changed,
int l, int t, int r, int b);
总结:
View 树的布局实际是给 每个view子节点的 mLeft, mTop, mRight, mBottom 四个成员变量赋值, 这四个成员变量代表 了 view 这个矩形框的位置和大小。