Android View 的繪制流程 - 開篇 MeasureSpec
Android View 的繪制流程 01 - 前置流程
Android View 的繪制流程 02 - performMeasure
Android View 的繪制流程 03 - performLayout
Android View 的繪制流程 04 - performDraw
耗時(shí)1個(gè)多月, 期間斷斷續(xù)續(xù)的看和學(xué)習(xí). 總算是把Android View 的繪制流程弄清楚了.
不過僅僅只是流程, 還有很多細(xì)節(jié)沒有學(xué)習(xí)到. 這就需要后面的不斷積累和查看源碼了. 有了流程, 再去看源碼, 就會(huì)覺得清晰了很多.
經(jīng)過這次學(xué)習(xí), 包括前面學(xué)習(xí)的 setContentView 流程, 再結(jié)合網(wǎng)上的一些博客, 大概的弄清了 Activity, DecorView, Window, ViewRoot 他們之間的關(guān)系
繪制了一張圖, 來代表 Android View 繪制的全部過程, 從 Activity 啟動(dòng)流程中調(diào)用 ActivityThread.handleLaunchActivity() 方法開始, 一直到 preforDraw() 結(jié)束. 圖中, 有什么不對(duì)的地方, 歡迎大家指正, 一起學(xué)習(xí),共同進(jìn)步.
現(xiàn)在需要對(duì) Android View 繪制流程做一些總結(jié)和一些網(wǎng)上收集到的.
只有在 onMeasure 測(cè)量的時(shí)候, 是一直遍歷到最后才開始測(cè)量葉子 View, 然后一級(jí)一級(jí)的再向上傳遞葉子 View 的測(cè)量結(jié)果.根據(jù)所有葉子View 的測(cè)量結(jié)果來測(cè)量父容器.
measure 過程中, 子View 是要根據(jù)父容器的測(cè)量規(guī)格與自己的屬性來確定自己的測(cè)量規(guī)格.
measure 完成后得到的是對(duì)每個(gè) View 經(jīng)測(cè)量過的 measuredWidth 和 measuredHeight.
layout 布局?jǐn)[放的時(shí)候, 真正執(zhí)行布局?jǐn)[放的方法是 View.setFrame() 方法. 根據(jù) onMeasure 測(cè)量結(jié)果進(jìn)行布局?jǐn)[放.
layout 完成之后得到的是對(duì)每個(gè) View 進(jìn)行位置分配后的 mLeft, mTop, mRight, mBottom, 這些值都是相對(duì)于父View來說的.
onDraw 需要我們自己去實(shí)現(xiàn),從而繪制內(nèi)容.
dispatchDraw 在 ViewGroup 已經(jīng)實(shí)現(xiàn)好了, 默認(rèn)會(huì)調(diào)用子 View 的 draw() 方法.
View 繪制的順序, 就是我們給一個(gè) ViewGroup 添加子View 的順序.
layout 是對(duì)本身 View 的布局, onLayout, 是對(duì)所有子 View進(jìn)行布局. layout 中 就是通過 setFrame() 方法設(shè)定本身 View 的四個(gè)頂點(diǎn)的位置, 這四個(gè)位置確定后, 本身 View 的位置就固定了. 然后調(diào)用 onLayout 來布局子View, View 和 ViewGroup 的 onLayout 方法都沒有實(shí)現(xiàn), 留給我們自己給子View布局
ViewGroup 默認(rèn)是不會(huì)執(zhí)行 onDraw 方法的. 因?yàn)?ViewGroup 多數(shù)只是負(fù)責(zé)布局, 不負(fù)責(zé) draw. 如果想要 ViewGroup 進(jìn)行 onDraw 怎么辦, 可以調(diào)用
setWillNotDraw(false)
方法, 里面參數(shù)傳 false 即可. ViewGroup 在初始化的時(shí)候, 默認(rèn)這個(gè)標(biāo)志位是 true. 如果我們自定義的 View 不需要 draw 的話, 就可以調(diào)用這個(gè)方法, 設(shè)置為 true. 這樣系統(tǒng)就知道這個(gè) View 是不需要繪制的. 可以優(yōu)化執(zhí)行速度. View 中 這個(gè)標(biāo)志位一半都是關(guān)閉的(false狀態(tài)).-
invalidate 方法和 View 繪制的關(guān)系.
invalidate 方法會(huì)會(huì)請(qǐng)求重繪 View 樹. 調(diào)用 draw 方法. 如果 View 的大小沒有發(fā)生變化就不會(huì)調(diào)用 layout 的流程, 并且只會(huì)繪制那些需要重繪的 View, 也就是哪個(gè) View 請(qǐng)求 invalidate, 就繪制該View. (View 就只繪制該 View, ViewGroup 就會(huì)繪制整個(gè) View Group)
直接調(diào)用 invalidate 方法, 會(huì)繪制調(diào)用者本身.
觸發(fā) setSelection 方法, 會(huì)繪制調(diào)用者本身.
觸發(fā) setVisibility 方法,
當(dāng) View 可視狀態(tài)在 INVISIBLE 轉(zhuǎn)換 VISIBLE 時(shí)會(huì)間接調(diào)用 invalidate 方法详羡,繪制該View.
當(dāng) View 的可視狀態(tài)在 INVISIBLE\VISIBLE 轉(zhuǎn)換為 GONE 狀態(tài)時(shí)會(huì)間接調(diào)用 requestLayout 和 invalidate 方法嘿悬,同時(shí)由于 View 樹大小發(fā)生了變化,所以會(huì)請(qǐng)求 measure 過程以及 draw 過程善涨,同樣只繪制需要“重新繪制”的視圖。觸發(fā) setEnabled 方法, 不會(huì)重新繪制任何 View 包括當(dāng)前調(diào)用者本身.
觸發(fā) requestFocus 方法, 只會(huì)繪制需要重繪的 View .