[譯]Android view 測量布局和繪制的流程
原文鏈接
創造優秀的用戶體驗是我們開發者的主要目標之一.為此, 我們首先要了解系統是如何工作的, 這樣我們才可以更好的與系統配合, 從它的優點中獲益, 規避它的缺陷.
之前關於Android渲染過程的文章
這次我們主要關註Measure/Layout(測量和布局)的階段, 這些階段決定了視圖的大小和位置, 以便於我們能夠繪制它.
Step 1: Measure 測量
目標: 確定是圖的大小
視圖的大小包含其子視圖的大小, 且必須符合其父視圖的要求
視圖的大小由2個方面決定:
- 測量寬度與測量高度 - 視圖在其父視圖中想要占據多大空間.這是此階段我們需要的大小.
- 寬度與高度(也就是繪制高度與繪制寬度)
How does it work?
- 自頂向下遞歸的遍歷view樹.
- 每個視圖將規格傳遞給子視圖.
如何實現?父視圖通過MeasureSpec
類的三種選項之一來決定子視圖的寬高:
UNSPECIFIED
- 未指定, 子視圖可以獲得任意大小EXACTLY
- 指定, 子視圖應該有指定大小AT_MOST
- 最大, 子視圖最大可達到某個值
每個視圖的寬高設置由ViewGroup.LayoutParams
的3種選項決定:
- 一個明確的數字
MATCH_PARENT
子視圖想要和父視圖一樣大WRAP_CONTENT
-
測量過程在
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
函數中完成 -
當這個函數返回時, 每個視圖都必須有
measuredWidth
和measuredHeight
(可由調用super()
完成), 否則會拋出IllegalStateException
.
Notice that this process sometimes a negotiation between a view and its children, and so measure() may be called more than once. More on that on a later post.
- 註意這個過程有時需要視圖和其子視圖互相協商, 因此
measure()
方法可能會被調用不止一次.
Since the traversal is top down, and each parent tells its children the requirements, we end up with our goal achieved:
Each view’s measured size includes its children size, and fit its parent requirements.
因為遍歷是自頂向下的, 並且沒個父視圖告訴子視圖其需求, 我們最終的目標是:
每個視圖的計算大小包含了子視圖的大小, 並符合其父視圖的要求
Step 2: Layout 布局
目標: 為視圖及其子視圖設定位置和大小(繪制寬度和繪制高度)
- 與step1類似: 自頂向下遞歸遍歷視圖樹.
- 每個父視圖通過上一個計算的大小定位其所有子視圖的位置.
- 定位由
onLayout(boolean changed, int left, int top, int right, int bottom)
方法完成, 其中left, top, right, bottom
是相對於其父視圖的. - 當重寫
onLayout()
方法時, 必須調用每個子視圖的layout()
方法.
Step 3: Draw 繪制
- 當大小和位置都確定之後, 視圖可以據此繪制自己.
- 在
onDraw(Canvas)
方法中Canvas
對象生成(或者是更新)一系列OpenGl-ES命令(displayList)發送給GPU.
這就是繪制的過程! 但是當我們改變了視圖的屬性時發生了什麽呢? 由動畫, 用戶輸入, 或者我們決定改變他們的時候.
When things change… 當發生改變時
當視圖屬性改變是, 視圖會通知系統. 取決於改變的屬性, 視圖調用下列之一:
invalidate
- 此時只會調用視圖的onDraw()
requestLayout()
- 會傳遞到根視圖, 然後調用整個過程(測量->布局->繪制)
對於需要布局的情況有一個經典的小例子: 我們在一個
RelativeLayout
中有兩個關系相對的視圖. 如果其中一個改變了大小 - 一定會導致另一個重新定位, 也可能導致父視圖改變大小.所以我們改變了一個視圖的屬性, 導致了整個布局都過期了.
這種情況提醒我們高效的布局是很重要的, 這樣布局才能流程的執行並且不會導致跳幀.
https://www.cnblogs.com/fortitude/p/8632171.html[譯]Android view 測量布局和繪制的流程