概述:
之前分析过activity调用setContentView之后的流程和基于FrameLayout的onMeasure流程分析,onMeasure流程走完之后,布局文件中的各个控件的宽度和高度就都测量完成了,接下来就是布局了,布局的功能就是确定每个控件的摆放位置,这里也就是上下左右,left,top,bottom,right。这一步进行完成后控件在屏幕上的位置就确定了,如下是流程图:
调用从ViewRootImpl中发起,这里直接对View调用了layout,而且还会兼容处理requestLayout请求。
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
mLayoutRequested = false;
mScrollMayChange = true;
mInLayout = true;
final View host = mView;
if (host == null) {
return;
}
......
try {
//调用布局方法
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
mInLayout = false;
int numViewsRequestingLayout = mLayoutRequesters.size();
//当前有重新布局请求
if (numViewsRequestingLayout > 0) {
// 能够进入到这里是因为有子view在布局期间调用了requestLayout
// 如果请求布局的view没有设置layout-request flags,那就没问题
// 如果依然有部分请求待执行,则需要清除所有flag,然后做一次完整的测量、布局才能解决这个问题
//获取可以重新布局的view,这里主要检测PFLAG_FORCE_LAYOUT和可见性
ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
false);
if (validLayoutRequesters != null) {
//这里将这个标记置为true为了让后面的其他layout请求都放到下一次执行
mHandlingLayoutInLayoutRequest = true;
//处理新的布局请求,然后进行测量和布局
int numValidRequests = validLayoutRequesters.size();
for (int i = 0; i < numValidRequests; ++i) {
final View view = validLayoutRequesters.get(i);
//将这些请求加入到mLayoutRequesters列表中
view.requestLayout();
}
//重新对view进行厕灵
measureHierarchy(host, lp, mView.getContext().getResources(),
desiredWindowWi