分析 draw 過程的源碼的時候,遇到一個很神奇的疑問:
ViewGroup.dispatchDraw 調(diào)用 dispatchDraw(Canvas) 的時候調(diào)用 View.draw 繪制子 View。將自己的 Canvas, 直接傳給了子 View。此時,Canvas 的繪圖區(qū)域應該是父 View 的繪圖區(qū)域(坐標系)。但是,View.onDraw(Canvas )獲取的 Canvas 的繪圖區(qū)域(坐標系)確是 View 的。Canvas 在哪里做的變換呢?
onDraw(Canvas) 是在 draw(Canvas) 方法里被調(diào)用的,但是 Draw 方法里也沒有看到 Canvas 做變換的代碼。
通過 Studio 分析源碼,父 View 調(diào)用 drawChild 的時候直接就跳到了子 View 的 Draw 方法里。Canvas 是在哪里做變換的?!

寫了一個 LinearLayoutDebug 類,在 dispatchDraw 時打印 canvas width 和 height 屬性:

再寫了一個 ViewDebug 類,在 draw(Canvas)時打印 Canvas width 和 height屬性:

打印結(jié)果是這樣:

Canvas 的 size 出現(xiàn)了 “突變”!真邪門!
不信邪,打斷點看看,怎么 drawChild 下一步到 Draw,Canvas 直接就做了變換。
斷點不知怎么跳的,因為看到的代碼不是 draw(Canvas),所以重新審視 Studio 的代碼自動跳轉(zhuǎn)。
再看,原來是 Studio 跳錯地方了!
再看一遍 gif,ViewGroup 調(diào)用的是 child.draw(Canvas,ViewGroup,long),但 Studio 卻跳到了 Draw(Canvas)去,Draw(Canvas,ViewGroup,long)被 Studio 省略了!

draw(Canvas,ViewGroup,long)
分析這個被 Studio “忽略” 了的方法,可以看到里面出現(xiàn)了 Matrix,canvas.translate 等代碼。draw(Canvas)也在 draw(Canvas,ViewGroup,long)里被調(diào)用。
結(jié)論
ViewGroup 傳給子 View 的是自己的 Canvas,子 View 在draw(Canvas,ViewGroup,long)方法里對 Canvas 做 了合適的變換,使 Canvas 的尺寸,坐標系等與子 View 自身的尺寸,位置相匹配。
View 在 draw(Canvas)里調(diào)用 drawBackground,onDraw,dispatchDraw 等方法完成自身的繪制。draw(Canvas)的 Canvas 已經(jīng)做了合適的變換,我們在重寫onDraw,dispatchDraw 等方法時不需要做變換。