文章

06.layout布局

layout 流程

ViewRootImpl#performTravasls 或调用 performLayout

performLayout 触发的条件:

1
2
3
4
5
6
7
// ...
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
        || mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
    performLayout(lp, mWidth, mHeight);
    // ...
  1. mLayoutRequested 为 true,即调用 requestLayout()
  2. 触摸模式发生变化
  3. decorview 宽高发生变化
  4. 内容边界是否发生变化
  5. Configuration 发生变化

performlayout 直接调用了 decorView.layout() 方法,即 ViewGroup 的 layout 方法

1
2
3
4
5
6
7
8
9
10
11
12
@Override
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;
    }
}

如果有 Transition 动画在执行则不调用 layout,否则调用 View.layout

View.layout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void layout(int l, int t, int r, int b) {
    if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
        onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
        mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
    }

    int oldL = mLeft;
    int oldT = mTop;
    int oldB = mBottom;
    int oldR = mRight;

    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);
    }
}
本文由作者按照 CC BY 4.0 进行授权