privatevoidperformLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight){ // 先将当前是否有布局请求的flag设置为false mLayoutRequested = false; mScrollMayChange = true; // 将当前正在布局的flag设置为true mInLayout = true; // 获取decorView final View host = mView; if (DEBUG_ORIENTATION || DEBUG_LAYOUT) { Log.v(TAG, "Laying out " + host + " to (" + host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")"); }
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout"); try { // 对decorView进行布局 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); // 将当前正在布局的flag设置为false mInLayout = false; // 获取当前请求布局的View的个数 int numViewsRequestingLayout = mLayoutRequesters.size(); if (numViewsRequestingLayout > 0) { // requestLayout() was called during layout. // If no layout-request flags are set on the requesting views, there is no problem. // If some requests are still pending, then we need to clear those flags and do // a full request/measure/layout pass to handle this situation. // 获取需要进行布局的View ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, false); if (validLayoutRequesters != null) { // Set this flag to indicate that any further requests are happening during // the second pass, which may result in posting those requests to the next // frame instead // 设置正在处理布局请求的flag为true mHandlingLayoutInLayoutRequest = true;
// Process fresh layout requests, then measure and layout // 获取需要进行布局的View的个数 int numValidRequests = validLayoutRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = validLayoutRequesters.get(i); Log.w("View", "requestLayout() improperly called by " + view + " during layout: running second layout pass"); view.requestLayout(); } measureHierarchy(host, lp, mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight); mInLayout = true; host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
mHandlingLayoutInLayoutRequest = false;
// Check the valid requests again, this time without checking/clearing the // layout flags, since requests happening during the second pass get noop'd validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); if (validLayoutRequesters != null) { final ArrayList<View> finalRequesters = validLayoutRequesters; // Post second-pass requests to the next frame getRunQueue().post(new Runnable() { @Override publicvoidrun(){ int numValidRequests = finalRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = finalRequesters.get(i); Log.w("View", "requestLayout() improperly called by " + view + " during second layout pass: posting in next frame"); view.requestLayout(); } } }); } }
上一篇的结尾中,我们发现了View的绘制发生在ViewRootImpl的performTraversals()中.而且在其中先后调用了performMeasure(),performLayout(),performDraw(). 如此一来,我们又有了新的猎物了.就像美食一样,好吃的东西一定要仔细地品尝.在上主菜之前,我们先来点开胃菜.我们先来了解一下Android是怎样绘制View的.(官方的文档How Android Draws Views)
/** * Set the activity content from a layout resource. The resource will be * inflated, adding all top-level views to the activity. * * @param layoutResID Resource ID to be inflated. * * @see #setContentView(android.view.View) * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) */ publicvoidsetContentView(@LayoutRes int layoutResID){ getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }