View繪制流程(測量,擺放,繪制)

\color{red}{View繪制流程(測量,擺放,繪制)}

起點ActivityThread.handleLaunchActivity()

一、ActivityThread.performLaunchActivity();

通過反射方式,創(chuàng)建Activity 實例,


\\新建Application實例。

Applicationapp=r.packageInfo.makeApplication(false,mInstrumentation);

\\執(zhí)行

mInstrumentation.callActivityOnCreate(activity,r.state,r.persistentState);

\\繼續(xù)調(diào)用

activity.performCreate(icicle,persistentState);

然后調(diào)用Activity的onCreate方法。

再執(zhí)行我們設置的setContentView操作。

getWindow().setContentView(view,params);

mWindow=newPhoneWindow(this);

執(zhí)行PhoneWindow的setContentview(), 先創(chuàng)建次頂層DecorView,每個activity都對應一個窗口window,這個窗口是PhoneWindow的實例,PhoneWindow對應的布局是DecorView,是一個FrameLayout,DecorView內(nèi)部又分為兩部分,一部分是ActionBar,另一部分是ContentParent,即activity在setContentView對應的布局。

接著ContentParent載入傳入的layoutResID

mLayoutInflater.inflate(layoutResID,mContentParent);

//接著會執(zhí)行

activity.performStart();

//對應

activity的onStart()

二、ActivityThread.handleResumeActivity()

執(zhí)行完performLaunchActivity接著執(zhí)行performResumeActivity(),執(zhí)行


activity.performResume()

//對應

activity的onResume()

然后開始執(zhí)行繪制工作

WindowManagerImpl.java

ViewManagerwm=a.getWindowManager();

Viewdecor=r.window.getDecorView();

wm.addView(decor,l);

///...

wm.updateViewLayout(decor,l);

wm=((WindowManagerImpl)wm).createLocalWindowManager(this);

接著執(zhí)行

WindowManagerGlobal.addView(view,params,mDisplay,mParentWindow);

//創(chuàng)建root

root=newViewRootImpl(view.getContext(),display);

//下一步

root.setView(view,wparams,panelParentView);

//下一步

requestLayout();

\color{red}{viewRootImpl是用于管理activity的view,其成員mView對應的就是activity的decorView,viewRootImpl設置decorView的方法是setView}

checkThread();就在requestLayout執(zhí)行。然后執(zhí)行scheduleTraversals();

然后通過回調(diào)的方式執(zhí)行doTraversal(); 接著執(zhí)行performTraversals()

然后執(zhí)行performMeasure()

ViewRootImpl.performMeasure(childWidthMeasureSpec,childHeightMeasureSpec);

//下一步,mView為FrameLayout

mView.measure(childWidthMeasureSpec,childHeightMeasureSpec);

//下一步

FrameLayout.onMeasure(widthMeasureSpec,heightMeasureSpec);

這時候FrameLayout遍歷子view(如果子View是ViewGroup,則繼續(xù)往下走)

然后執(zhí)行:

FrameLayout.measureChildWithMargins(child,widthMeasureSpec,0,heightMeasureSpec,0);

 protected void measureChildWithMargins(View child,
            int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                        + heightUsed, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

如圖中,childWidthMeasureSpec和childHeightMeasureSpec是計算后,子view的寬和高的大小以及測量模式。

\color{red}{這個模式需注意一個特殊的地方,就是當parent為AT_MOST的時候,即使子view設定為MATCH_PARENT,也會強制把子view的測量模式重置為AT_MOST。}

然后調(diào)用


child.measure(childWidthMeasureSpec,childHeightMeasureSpec);

//接著調(diào)用子view的onMeasure(widthMeasureSpec,heightMeasureSpec);

當子view計算完之后,parent(viewgroup)會根據(jù)子view的寬高計算自己的寬高,并設置自己的寬高。

即整個繪制過程是由外層開始往里,外層測量模式對子view的測量有影響,一層層往里調(diào)用,先測量最里層的view,然后逐步往外層,外層根據(jù)子view的寬高測量并設置自己的寬高。

\color{red}{參考示意圖:}

1544412578294_3.png

這樣,測量就結束了

接下來,執(zhí)行performLayout();

performDraw()

先畫外層的背景色,然后調(diào)用view的draw方法,先調(diào)用子view的dispachDraw(ViewGroup)或者onDraw(View)方法,

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容