4.1 初識 ViewRoot 和 DecorView
- ViewRoot 對應於 ViewRootImpl 類,連接 WindowManager 和 DecorView 的紐帶
- View 的三大流程均通過 ViewRoot 完成
ViewRoot#performTraversals
ViewGroup View
performMeasure measure onMeasure measure
performLayout layout onLayout layout
performDraw draw onDraw draw
- DecorView 其實是一個 FrameLayout
4.2 理解 MeasureSpec
- MeasureSpec:一個32位int值,高2位代表SpecMode(測量模式),低30位代表SpecSize(規格大小)
模式 |
簡介 |
UNSPECIFIED |
要多大就多大 |
EXACTLY |
精確模式,match_parent、具體數值 |
AT_MOST |
最大模式, wrap_content |
- 對於 DecorView ,MeasureSpec 由窗口尺寸和自身的 LayoutParams 共同決定
- 普通 View,由 父容器的 MeasureSpec 和自身 LayoutParams 決定。
結論(getChildeMeasureSpec) |
View採用固定寬/高,不管父容器 MeasureSpec 是什麼,View的 MeasureSpec 都是 精確模式 |
View 爲 match_parent,1.父容器是精確模式,View是精確模式,大小是父容器剩餘空間;2.父容器是最大模式,View也是最大模式,大小不會超過父容器剩餘空間 |
View的寬/高是wrap_content,不管父容器是精確還是最大化,View模式總是最大化,並且不能超過父容器剩餘空間 |
4.3 View 的工作流程
流程 |
View |
ViewGroup |
measure(測量) |
1.measure就完成測量過程;2.measure是一個final,子類不可重寫,看onMeasure ;3.onMeasure中getMeasuredWidth/Height拿到View寬高,可能不準,需要 onLayout 方法中;4.Activity/View#onWindowFocusChanged;5.view.post();6.ViewTreeObserver(getViewTreeObserver().addOnGlobalLayoutListener);7.view.measure(補充) |
1.完成自己測量過程,還要遍歷去調用所有子元素measure方法,各個子元素在measure;2.measureChildren;3.onMeasure 需要子類去重寫 |
layout(佈局) |
1.layout 確定 View 本身位置;2.步驟:setFrame設定View四個頂點位置,接着調用 onLayout 方法,用途是父容器確定子元素位置;3.onLayout 與具體佈局有關,View 和 ViewGroup 均沒有真正實現 onLayout |
|
draw(繪製) |
1.繪製背景backgroud.draw(canvas);2.繪製自己(onDraw);3.繪製children(dispatchDraw);4.繪製裝飾;(onDrawScrollBars)。 5.setWillNotDraw,如果一個View不需要繪製任何內容,設置 true,系統優化 |
|
view.measure
1.具體的數值
int width = MeasureSpec.makeMeasureSpec(100,MeasureSpec.EXACTLY)
int heigth= MeasureSpec.makeMeasureSpec(100,MeasureSpec.EXACTLY)
view.measure(width ,heigth)
2.wrap_content
int width = MeasureSpec.makeMeasureSpec((1<<30)-1,MeasureSpec.AT_MOST)
int heigth= MeasureSpec.makeMeasureSpec((1<<30)-1,MeasureSpec.AT_MOST)
view.measure(width ,heigth)
- getWidth/getMeasureWidth 區別
在View默認實現中,View測量寬/高和最終寬高相等,只不過測量寬高形成與View的measure,而最終寬高形成View的layout過程。
4.4 自定義 View
4.4.1 自定義View分類
分類 |
|
繼承View重寫OnDraw |
wrap_content,padding |
繼承ViewGroup派生特殊Layout |
測量、佈局 |
繼承特定View(tv) |
|
繼承特定ViewGroup(ll) |
|
須知 |
|
讓View支持wrap_content |
在 onMeasure 中對 wrap_content |
如果有必要,讓Viw支持padding |
draw 中處理 padding,直接繼承 ViewGroup 要在 onMeasure 和 onLayout 彙總 考慮 padding 和 子元素 margin 對其造成的影響,不讓導致 padding 和 子元素 margin 失效 |
儘量不要在view中使用Handler |
post |
如果有線程或動畫,要及時停止,參考 View#onDetachedFromWindow |
|
View帶有滑動嵌套情形時,需要處理滑動衝突 |
|