當一個活動接收到焦點時,它將被要求繪製它的布局。Android架構將處理這個繪畫的過程,但是活動必須提供它的布局層次的根節點。
繪畫從布局的根節點開始。它被要求來測量和繪製布局樹。繪畫通過遍曆布局樹並渲染每個和失效地區相交的視圖來處理。相應的,每個視圖組負責請求繪製它的子視圖(通過draw() 方法)而每個視圖負責畫它自己。因為這個樹是順序遍曆的,這意味著先畫父節點(也就是在螢幕後面),然後按照樹中出現的順序畫其同層次節點。
架構將不會畫不在失效地區的視圖,而且還將會幫你畫視圖背景。
你可以強制一個視圖被重畫,通過調用invalidate()。
繪畫布局共有兩步:一個度量過程和一個版面配置階段。度量過程在measure(int, int)裡實現且是一個自頂向下的視圖樹遍曆。每個視圖在遞迴時往下推送尺寸規格。在度量過程的最後,每個視圖都已經儲存了自己的度量。第二個過程發生在layout(int, int, int, int) 中並且也是自頂向下。在這個過程中,每個父節點負責定位它的所有子節點,通過使用在度量過程中計算得到的尺寸。
當一個視圖的measure()方法返回時,它的getMeasuredWidth()和getMeasuredHeight() 值必須被設定,以及所有這個視圖子節點的值。一個視圖的度量的寬度和高度值必須符合父視圖引入的限制。這確保在度量過程之後,所有父節點接受所有它們的子節點的度量值。一個父視圖可能會在其子視圖上多次調用measure()方法。比如,父視圖可能會通過未指定的尺寸調用measure來發現它們的大小,然後使用實際數值再次調用measure(),如果所有子視圖未做限制的尺寸總合過大或過小(也即是,如果子視圖之間不能對各自佔據的空間達成共識的話,父視圖將會幹預並設定第二個過程的規則)。
要開始一個布局,可調用requestLayout()。這個方法通常在視圖認為它自己不再適合它當前的邊界的情況下被調用。
度量過程使用兩個類來交流尺寸。View.MeasureSpec類被視圖用來告訴它們的父視圖它們想如何被度量和定位。基礎的LayoutParams類僅僅描述了視圖想有多大(高和寬)。對於每個維度,它可以指定下面之一:
- · 一個準確的數值
- · FILL_PARENT, 這意味著視圖想和父視圖一樣大(減掉填充padding)。
- · WRAP_CONTENT, 這意味著視圖只想有剛好封裝其內容那麼大(加上填充)
對於不同的ViewGroup子類,有相應的LayoutParams子類。比如,相對布局RelativeLayout有它自己的LayoutParams子類,這包含了能夠讓子視圖橫向和豎向置中顯示的能力。
度量規格(MeasureSpecs)被用來沿著樹從父到子的下傳度量需求。一個MeasureSpecs可以是下面三種模式之一:
- · UNSPECIFIED: 這被父視圖用來決定其子視圖期望的尺寸。比如,一個線性布局可能在它的子視圖上調用measure() on its child,通過設定其高度為UNSPECIFIED 以及一個寬度為EXACTLY 240,來找出這個子視圖在給定240像素寬度的情況下需要顯示多高。
- · EXACTLY: 這被父視圖用來給子視圖強加一個準確的尺寸。子視圖必須使用這個大小,並確保其所有的後代將適合這個尺寸。
- · AT_MOST: 這被父視圖用來給子視圖強加一個最大尺寸。子視圖必須確保它自己以及所有的後代都適合這個尺寸。
參考:SDK文檔http://developer.android.com/guide/topics/ui/how-android-draws.html