最近我的同事遇到了一個很有趣的問題。下面這個非常簡單的佈局會向我們展示一些關於Android測量系統的有趣發現。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
; html-script: false ] <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:background="#0F0" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is some text." /> </FrameLayout> |
預期的執行結果,應該顯示帶顏色背景的文字。但實際上,你根本就看不到背景ImageView:
問題的根源就在於測量。因為我們使用了顏色來代替了圖片,所以ImageView很自然地認為它的寬和高都是零。Colors(或者ColorDrawables)並沒有像圖片那樣具有實質意義上的大小,而ImageView不會大於它的背景或者圖片源的大小。
有意思的是,我們可以想出很多方法來解決這個問題。每個解決方法都揭示了測量系統的某個新的方面。從直觀的角度依次瞭解:
- 將父佈局FrameLayout設定為match_parent。這樣,ImageView就可以知道具體的大小,以此充滿父檢視。
- 使用View代替ImageView。View會擴張並填充空間,而ImageView不會。
- 使用RelativeLayout代替FrameLayout。相對佈局在測量子檢視大小時,會採用不同的方式。
- 為TextView寬或高設定為match_parent。這是個很讓人困惑的方法。它之所以有效,是因為如果FrameLayout有一個或多個子檢視使用了match_parent,會再做一次測量。
理解而不是簡單地解決這個問題,需要反覆閱讀FrameLayout.onMeasure()和ImageView.onMeasure()程式碼。面對這樣的問題,Android是開源專案這一事實讓我感到非常高興。
這個問題的核心在於,僅僅展示顏色不應該使用ImageView,用一個帶背景的View會更加可靠。
很顯然,上面的佈局沒有什麼實質意義,大家一般都會給TextView設定背景。不過,這是一種說明問題的簡單方式。