美文网首页Android进阶
View绘制流程(测量,摆放,绘制)

View绘制流程(测量,摆放,绘制)

作者: 天宇666 | 来源:发表于2019-01-02 11:58 被阅读0次

\color{red}{View绘制流程(测量,摆放,绘制)}

起点ActivityThread.handleLaunchActivity()

一、ActivityThread.performLaunchActivity();

通过反射方式,创建Activity 实例,


\\新建Application实例。

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

\\执行

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

\\继续调用

activity.performCreate(icicle,persistentState);

然后调用Activity的onCreate方法。

再执行我们设置的setContentView操作。

getWindow().setContentView(view,params);

mWindow=newPhoneWindow(this);

执行PhoneWindow的setContentview(), 先创建次顶层DecorView,每个activity都对应一个窗口window,这个窗口是PhoneWindow的实例,PhoneWindow对应的布局是DecorView,是一个FrameLayout,DecorView内部又分为两部分,一部分是ActionBar,另一部分是ContentParent,即activity在setContentView对应的布局。

接着ContentParent载入传入的layoutResID

mLayoutInflater.inflate(layoutResID,mContentParent);

//接着会执行

activity.performStart();

//对应

activity的onStart()

二、ActivityThread.handleResumeActivity()

执行完performLaunchActivity接着执行performResumeActivity(),执行


activity.performResume()

//对应

activity的onResume()

然后开始执行绘制工作

WindowManagerImpl.java

ViewManagerwm=a.getWindowManager();

Viewdecor=r.window.getDecorView();

wm.addView(decor,l);

///...

wm.updateViewLayout(decor,l);

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

接着执行

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

//创建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执行。然后执行scheduleTraversals();

然后通过回调的方式执行doTraversal(); 接着执行performTraversals()

然后执行performMeasure()

ViewRootImpl.performMeasure(childWidthMeasureSpec,childHeightMeasureSpec);

//下一步,mView为FrameLayout

mView.measure(childWidthMeasureSpec,childHeightMeasureSpec);

//下一步

FrameLayout.onMeasure(widthMeasureSpec,heightMeasureSpec);

这时候FrameLayout遍历子view(如果子View是ViewGroup,则继续往下走)

然后执行:

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。}

然后调用


child.measure(childWidthMeasureSpec,childHeightMeasureSpec);

//接着调用子view的onMeasure(widthMeasureSpec,heightMeasureSpec);

当子view计算完之后,parent(viewgroup)会根据子view的宽高计算自己的宽高,并设置自己的宽高。

即整个绘制过程是由外层开始往里,外层测量模式对子view的测量有影响,一层层往里调用,先测量最里层的view,然后逐步往外层,外层根据子view的宽高测量并设置自己的宽高。

\color{red}{参考示意图:}

1544412578294_3.png

这样,测量就结束了

接下来,执行performLayout();

performDraw()

先画外层的背景色,然后调用view的draw方法,先调用子view的dispachDraw(ViewGroup)或者onDraw(View)方法,

相关文章

网友评论

    本文标题:View绘制流程(测量,摆放,绘制)

    本文链接:https://www.haomeiwen.com/subject/rlxzlqtx.html