標籤:
轉載請註明出處:http://blog.csdn.net/hejjunlin/article/details/52236145
- View的Draw時序圖
- ViewRootImpl.performTraversals過程
- ViewRootImpl.performDraw過程
- View.draw方法
- View.dispatchDraw過程
- LinearLayout的onDraw過程
View的Draw時序圖
前面幾篇通過對View樹的measure和layout過程分析事,接下來將結合前兩步得到的測量值及在視圖中的位位置,開始進行繪製操作,一步比一步複雜,draw過程比前面都要複雜,draw的不好,就會出現overdraw。下面請仔細看分析過程:
draw的原始觸發點還是在ViewRootImpl的performTraversals(執行遍曆)方法中,開始分析流程:可以結合我畫的時序圖一起看,方便理解。
ViewRootImpl.performTraversals()
ViewRootImpl.performDraw()
ViewRootImpl.draw()
measure和layout過程直接調用的是ViewRootImpl的performMeasure和performLayout方法,draw調用的是ViewRootImpl的performDraw()方法,再由performDraw中的draw(boolean fullRedrawNeeded)方法來調用ViewTreeObserver中的dispatchOnDraw()方法,進行通知所有掛在view樹上的view開始draw。
ViewTreeObserver.dispatchOnDraw()
View.onDraw()
對於View.java和ViewGroup.java,onDraw()預設都是空實現,因為具體View本身是什麼,這就是做架構,提供空間,你要在裡面自訂什麼view是使用者所決定,但是可以提供預設方法。
View.draw()
View的另一個draw方法
View.drawBackground() — // Step 1, draw the background
View.onDraw() — // Step 3, draw the content
View.dispatchDraw() — // Step 4, draw the children
View.onDrawScrollBars — // Step 6, draw decorations (foreground, scrollbars)
View中dispatchDraw()預設為空白實現,因為其不包含子view,而ViewGroup重寫了dispatchDraw()來對其子view進行繪製,一般自訂view不應該對dispatchDraw()進行重載,因為它已經體現了View系統繪製的流程。那麼,接下來我們繼續分析下ViewGroup中dispatchDraw()的具體流程:
ViewGroup.dispatchDraw()
ViewGroup.drawChild()
- dispatchDraw()的關鍵就是通過for迴圈調用drawChild()對ViewGroup的每個子視圖進行繪製,上述代碼中如果FLAG_USE_CHILD_DRAWING_ORDER為true,則子視圖的繪製順序通過getChildDrawingOrder來決定,預設的繪製順序即是子視圖加入ViewGroup的順序,而我們可以重載getChildDrawingOrder方法來更改預設的繪製順序,讓子view重疊在父view上,或者說是掛在父view上。
- drawChild()的核心就是為子視圖分配合適的canvas畫布區,畫布區的size是d在layout過程決定的,而畫布區的位置取決於滾動值以及子視圖當前的動畫。設定畫布區後就會調用childview的draw()函數,如果childview的包含SKIP_DRAW標識,僅調用dispatchDraw(),即跳過子視圖本身的繪製,但要繪製視圖可能包含的childview。
ViewGroup.drawChild()
Draw過程小總結:
- 自訂View是一個ViewGroup,則需要遞迴繪製包含的所有子View。
- View預設不會繪製任何內容,真正的繪製都需要自己在子類中實現,只是做好繪製流程,這就是架構的職責。
- 區分View動畫和ViewGroup布局動畫,前者指的是View自身的動畫,可以通過setAnimation添加,後者是專門針對ViewGroup顯示內部子視圖時設定的動畫,可以在xml布局檔案中對ViewGroup設定layoutAnimation屬性(譬如對LinearLayout設定子View在顯示時出現逐行、隨機、下等顯示等不同動畫效果)。
- 在擷取畫布剪下區(每個View的draw中傳入的Canvas)時會自動處理掉padding,子View擷取Canvas不用關注這些邏輯,只用關心如何繪製即可。
- 預設情況下子View的ViewGroup.drawChild繪製順序和子View被添加的順序一致,但是你也可以重載ViewGroup.getChildDrawingOrder()方法提供不同順序。
第一時間獲得部落格更新提醒,以及更多android乾貨,源碼分析,歡迎關注我的公眾號,掃一掃下方二維碼或者長按識別二維碼,即可關注。
如果你覺得好,隨手點贊,也是對筆者的肯定,也可以分享此公眾號給你更多的人,原創不易
Android View架構總結(六)View布局流程之Draw過程