Android如何繪製視圖
當一個activity接收到焦點的時候,它將會被要求繪製介面布局。Android的framework將會處理繪製的過程,但是activity必須提供布局層的根節點。
繪製是從布局層的根節點開始的。它要度量和繪製布局樹。繪製是通過遍曆整個布局樹然後渲染那些交叉於無效地區的視圖。反之,每一個view group負責請求它的孩子進行繪製並且每一個則view負責自身。由於樹的遍曆是有序的,這就意味著父親將會比孩子先繪製,並同其它繪製過的兄妹在樹中有序出現。
繪製布局有兩個階段的過程:一個測量的階段和布局的階段。測量階段是靠實現measure(int, int)方法,並且會從上自下遍曆整個view樹。每一個view在遞迴過程中會將尺寸往下拉動。在測量的最後階段,每一個視圖都都儲存了自身的度量值。第二個階段發生在layout(int, int, int, int) 並且也是從上自下的。在這個階段沒一個父親負責使用在度量階段計算的尺寸來定位它的孩子。
當每一個視圖的measure()方法返回的時候,同那些所有的視圖後代一起,它的getMeasuredWidth() , getMeasuredHeight()的值必須被設定。View的可度量的寬和高必須要遵照view的父親所給的限制。這保證了在度量的最胡階段,所有的父親接受它們的孩子的度量值。一個父親view可以在它的孩子上多次調用measure()方法,例如,父親可以用不明確的尺寸發現他們到底需要多大來度量每一個孩子,然後再次調用measure()方法,當孩子的沒受限制的尺寸的總和太大或是太小,就會使用實際的資料
。
度量階段使用兩個類來和尺寸互動。View.MeasureSpec類被view用來告訴它們的父親他們想被如何度量和擺放。LayoutParsms 類只是描述view需要多寬和多高。對於每一個尺寸,可以指定為下面的之一:
- 一個確切的數字
- FILL_PARENT, 這意味著視圖想要和它的父親一樣大
- WRAP_CONTENT, view只想包裹住自己的內容
LayoutParams的子類對應不同的ViewGroup的子類。例如,相對布局有它自己的LayoutParams的子類,包含了可以讓子視圖在中央水平和垂直布局的能力。
MeasureSpecs被用來將需求從樹的父親到孩子往下推進。MeasureSpecs只能是下面樹模式中的一種:
- UNSPECIFIED: 這被父親用來決定需要哪個尺寸的子視圖。例如,一個線性布局可以在它的孩子上調用measure()方法,並將高度設定為UNSPECIFIED,寬度為EXACTLY 240來發現子視圖需要被給的240像素的高度有多高。
- EXACTLY: 被父view用來給子view強加一個精確的大小。子view必須是這個大小,並確保它的後代都在這個大小範圍之內。
- AT_MOST: 被父view用來強加一個最大的大小給子view。子view必須是這個大小,並確保它的後代都在這個大小範圍之內。