一:View是如何被添加到屏幕窗口的命锄。
打開Activity,在oncreat()方法里面镰吆,調(diào)用了setContentView()方法护盈,方法參數(shù)傳入布局文件。調(diào)用流程:??
setContentView()-->getWindow().setContentView()【getWindow是Window類中的方法闲先,Window繼承了抽象的PhoneWindow】--->實(shí)際調(diào)用了PhoneWindow中的setContentView()方法-->調(diào)用instalDecor()
方法状土,在此方法中首先調(diào)用generateDecor()方法,創(chuàng)建DecorView對象伺糠,其次調(diào)用了generateLayout()方法首先根據(jù)features不同初始化不同的layoutResource(基礎(chǔ)容器)-->通過onResourceLoaded()方法把layoutResource進(jìn)行解析蒙谓,并添加到DecorView容器上。然后在generateLayout()方法中通過findViewByID找到R.id.conent的容器退盯,該容器為FrameLayout彼乌,把通過setContentView()方法傳遞進(jìn)入的布局文件解析到FrameLayout容器中泻肯。
總結(jié):首先系統(tǒng)會創(chuàng)建一個頂層的容器DecorView渊迁,DecorView是ViewGroup繼承FrameLayout慰照,是PhoneWindow持有的一個實(shí)例,DecorView是所有應(yīng)用程序的頂層View琉朽,在系統(tǒng)內(nèi)部進(jìn)行初始化毒租,當(dāng)DecorView完成初始化之后系統(tǒng)不根據(jù)當(dāng)前應(yīng)用程序的主題特性,加載一個基礎(chǔ)容器箱叁,例如:no_action_bar,dark_action_bar墅垮。不同的主題加載的基礎(chǔ)容器不同,但基礎(chǔ)容器都存在R.id.content的FrameLayout的容器耕漱,我們開發(fā)者通過setContentView設(shè)置的布局文件(xml文件)就是通過解析之后加載到FrameLayout中的算色。
二:View的繪制流程
1:繪制入口
ActivitytThread.handleResumeActivity()--->WindowManagerImpl.addView(decorView,layoutParams)-->WindowManagerGlobal.addView(),此方法會創(chuàng)建出ViewRootImpl對象
2:繪制類及方法
ViewRootImpl.setView(decorView,layoutParams,parentView)將decorView與布局屬性,布局進(jìn)行關(guān)聯(lián)--->ViewRootImpl.requestLayout()--->ViewRootImpl.scheduleTraversals()--->子線程調(diào)用doTraversals()--->performTraversals()螟够,次方法是真正繪制的方法灾梦。
3:繪制三大步驟
測量:ViewRootImpl.performMeasure();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 布局:ViewRootImpl.performLayout();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 繪制:ViewRootImpl.performDraw();
總結(jié):當(dāng)Activity創(chuàng)建之后,在Activty的handlResumeActivity()方法中通過VM調(diào)用了addView方法妓笙,VM找到實(shí)現(xiàn)類WindowManagerImpl若河,調(diào)用addView()方法,addView第一個參數(shù)是頂層的DecorView寞宫,第二個參數(shù)是布局屬性萧福。接著調(diào)用WindowManagerGloabl.addView()方法,再次方法中會創(chuàng)建ViewRootImpl對象辈赋,調(diào)用setView()方法鲫忍,將DecorView,布局屬性钥屈,布局進(jìn)行關(guān)聯(lián)饲窿,關(guān)聯(lián)成功后ViewRootImpl準(zhǔn)備繪制,調(diào)用了ViewRootImpl的requestLyaout()方法,然后調(diào)用了schedluTraversals(),在子線程調(diào)用了doTraversals()方法焕蹄,在調(diào)用了perFormTraversals(),次方法是真正真正繪制的方法逾雄。
4:詳細(xì)步驟(測量)
(1)View的測量包含兩部分模式+尺寸,被封裝到了MeasureSpec
? ? MeasureSpec:是一個32位int類型的值腻脏,前面2位是模式鸦泳,后面30位是尺寸。是View 的測量規(guī)格? ? ? ? ? ? ? ? ? view的測量 = specMode (模式) + specSize(尺寸)永品。
? ?makeMeasureSpec方法把模式和尺寸打包生成成MeasureSpec
???a:?3種測量模式做鹰。? MODE_SHIFT = 30 位? ? ? ?MODE_MASK =0x3 <<MODE_SHIFT
? ? UNSPECIFIED? ?0<<MODE_SHIFT? 父容器不對View做任何限制,一般系統(tǒng)使用鼎姐。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? EXACTLY? ? ? ? ? 1<<MODE_SHIFT? 父容器檢測view的大小钾麸,view的大小就是specSize 更振,布局屬性? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? layoutParams子控件match_parent 或者固定大小。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?AT_MOST? ? ? ? ?2<<MODE_SHIFT? 父容器指定一個可用大小specSize饭尝,view最大不能超過這個值肯腕,布? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 局屬性子控件 layoutParams為wrap_content
b:頂層View -------確定DecorView的MeasureSpec
?DecorView的MeasureSpec由窗口大小,自身的LayoutParsms決定钥平。
自身LayoutParsms.MATCH_PARENT:精確模式实撒,大小為窗口大小,模式為 EXACTLY.
自身LayoutParsms.WRAP_CONTENT:最大模式涉瘾,大小最大為窗口大小知态,模式為 AT_MOST.
固定大小:精確模式立叛,大小自身LayoutParsms的大小负敏,模式為 EXACTLY.
View測量
ViewGroup? ?mesure()---->onMeasure(測量子控件的寬高)--->setMeasureDimesion()-->setMeasureDimesionRaw(保存自己的寬高)
View? ? ?mesure()---->onMeasure()--->setMeasureDimesion()-->setMeasureDimesionRaw(保存自己的寬高)
View 的布局
ViewGroup? ?layout(來確定自己的位置,4個點(diǎn)左上右下)--->onLayout(進(jìn)行子View的布局)
View? ? ? ? ? ? ?layout(來確定自己的位置秘蛇,4個點(diǎn)左上右下)
View的繪制
ViewGroup
(1)繪制背景? drawBackGround(canvas)
(2)繪制自己? onDraw(canvas)
(3)繪制子View dispatchDraw(canvas)
(4)繪制前景其做,滾動條等裝飾 onDrawForeground(canvas)
View
(1)繪制背景? drawBackGround(canvas)
(2)繪制自己? onDraw(canvas)
(3)繪制子View dispatchDraw(canvas)
(4)繪制前景,滾動條等裝飾 onDrawForeground(canvas)