View 的 requestLayout() 方法顾名思义用来触发一次 layout 行为,一般是当我们改变一些影响 View 布局的参数后调用,刷新 View 的布局。常见的使用方式如下:
view.layoutParams.apply{
width = 100
height = 200
}
view.requestLayout()
复制代码
要分析调用失效的原因,首先我们需要搞清楚 requestLayout() 流程。
requestLayout 调用流程
调用 requestLayout() 之后是如何开始一次 layout 的呢?我们看一下 requestLayout() 的源码:
public void requestLayout() {
if (mMeasureCache != null) mMeasureCache.clear();
if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
// Only trigger request-during-layout logic if this is the view requesting it,
// not the views in its parent hierarchy
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null && viewRoot.isInLayout()) {
if (!viewRoot.requestLayoutDuringLayout(this)) {
return;
}
}
mAttachInfo.mViewRequestingLayout = this;
}
mPrivateFlags |= PFLAG_FORCE_LAYOUT;
mPrivateFlags |= PFLAG_INVALIDATED;
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
mAttachInfo.mViewRequestingLayout = null;
}
}
复制代码
这个方法逻辑比较简单,首先是将 MeasureCache 清掉,为即将开始的 layout 做准备。接下来一段代码根据注释应该是 request-during-layout 的逻辑,这部分我们先略过后面再讲。再下来的代码是这个方法的核心:设置绘制状态位和调用 parent 的 requestLayout。PFLAG_FORCE_LAYOUT 表示当前 View 需要 layout,可以理解为 View 当前的布局数据已经过期,需要下一次 layout pass 重新布局,PFLAG_INVALIDATED 和 PFLAG_FORCE_LAYOUT 类似,只不过表示的是绘制数据。为什么要调用 parent 的 requestLayout() 这里稍微解释下,因为父 View 是包含着子 View 的,子 View 的布局一般决定着父