系列文章目录
文章目录
- 一、 从0开始实现 onCreate 的setContentView
- 二、 从0 开始实现 onMeasure
- 三、 从0 开始实现 onLayout
- 四、 从0 开始实现 onDraw
- 总结
前言
接上文,测量完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 finishesmLayoutCalledWhileSuppressed = true;}
}protected abstract void onLayout(boolean changed,int l, int t, int r, int b);
总结:
View 树的布局实际是给 每个view子节点的 mLeft, mTop, mRight, mBottom 四个成员变量赋值, 这四个成员变量代表 了 view 这个矩形框的位置和大小。