[翻譯] Android是怎樣繪製視圖的,android繪製
原文:How Android Draws Views
當一個Activity擷取到焦點的時候,它的布局就開始被繪製。
繪製的過程由Android framework處理。但布局層級的根節點必須由Activity提供。
視圖的繪製由布局的根節點開始,通過遍曆布局樹和渲染每個和無效地區交叉的視圖,整個布局和它的子布局(layout tree)都會被測量並繪製。反過來,ViewGroup的職責是請求它的每個子項目被繪製(通過draw()方法),而每個View的職責則是繪製它們自己本身。(意思是ViewGroup只負責排位,而view自己負責繪製工作)因為元素是 按順序排列的,因此,父元素總是先於子項目被繪製,而父元素的同層級元素則按照它們出現的先後順序繪製。
布局的繪製分為兩個過程: 測量過程和版面配置階段.
測量過程在measure(int,int)方法中實現。它是按照view tree的排列從上到下進行測量的。在測量過程結束後,每個View都儲存了自己的尺寸。
版面配置階段在layout(int, int, int, int)方法中實現,它也是從上而下進行的。在這個過程中,子項目的父節點根據子項目在上一個步驟中取得的值安排好它們的位置。
當一個View的measure()方法返回的時候,它的getMeasuredWidth()和getMeasuredHeight()的值必須被設定好。當View的父元素對這個子View的寬高值有限制的時候,這個子View必須遵守這個限制。這樣做能保證在測量過程結束的時候,子View的寬高值能被父元素所接受。一個父View可能會對它的子View調用多次measure方法。舉個例子,父View第一次調用measure()方法是為了擷取子View請求的寬高,寬高值取得後,父View會根據這些值再次調用measure方法,進而檢測這些值是否超出了限制(太大或是太小),如果是,則父View會在第二個過程中進行限制。
在測量過程中,子項目可以使用ViewGroup.LayoutParams類告知父元素它們所請求的尺寸。
ViewGroup.LayoutParams包含兩個值:
MATCH_PARENT:子項目需要和父元素一樣大(減去補白[padding])
WRAP_CONTENT:子項目只需要剛好能夠放置它們的內容 (加上padding)
ViewGroup不同的子類有不同的LayoutParams。例如,RelativeLayout也有自己的LayoutParams類。
這使得RelativeLayout可以在水平和垂直方向上在中心放置子項目.
而父元素則可以通過MeasureSpec類限制子項目的尺寸。MeasureSpec的值可以是下面三個中的其中一個。
UNSPECIFIED:單純用於擷取子項目請求的值,不對子項目設定限制。例如:LinearLayout可以對它的子項目的長和寬分別設定為UNSPECIFIED和EXACTLY的值為240,這樣可以知道當給子項目的長是240px的時候,它所需要的高度度會是多少。
EXACTLY:父元素將子項目的值限制為指定的值。子項目必須使用這個值,並且保證它的所有後代元素在這個尺寸內可用。
AT_MOST:父元素指定子項目的最大尺寸。子項目必須保證它和它的所有後代元素在這個尺寸內可用。
注意:Android framework不會繪製不在無效地區的View,而且會負責繪製View的背景。
我們可以通過調用invalidate()方法強制一個View重新繪製。
通過調用requestLayout()初始化布局。當一個View對象認為現在的地區已經無法正常工作的時候就會調用這個方法。
關於有效地區和無效地區:無效地區是需要被更新的地區,有效地區無須被更新。
有windows 開發經驗的人都應該知道,當一個視窗從被遮擋到出現,視窗會重新被繪製,而這個被遮擋的地區就是無效地區。因為當這個地區再次出現的時候,我們必須保證它的內容是最新的,因此需要被更新,即重新繪製.
有效地區之所有被稱為有效地區,是因為它目前的狀態已經是最新的,不需要更新,所以不需要被重繪。