轉載自google官方,地址:https://developer.android.com/intl/zh-cn/training/multiscreen/screensizes.html#TaskUseWrapMatchPar
此教程將向您介紹如何通過以下方法支持各種尺寸的屏幕:
- 確保系統可以適當地調整您佈局的尺寸以便適應屏幕
- 根據屏幕配置提供合適的用戶界面佈局
- 確保正確的佈局應用到了正確的屏幕上
- 提供可正確縮放的位圖
使用“wrap_content”和“match_parent”
要確保佈局的靈活性並適應各種尺寸的屏幕,您應使用 "wrap_content"
和 "match_parent"
控制某些視圖組件的寬度和高度。如果您使用 "wrap_content"
,系統就會將視圖的寬度或高度設置成所需的最小尺寸以適應視圖中的內容,而 "match_parent"
(在低於 API 級別 8 的級別中稱爲 "fill_parent"
)則會展開組件以匹配其父視圖的尺寸。
如果使用 "wrap_content"
和 "match_parent"
尺寸值而不是硬編碼的尺寸,您的視圖就會相應地僅使用自身所需的空間或展開以填滿可用空間。例如:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:id="@+id/linearLayout1" android:gravity="center" android:layout_height="50dp"> <ImageView android:id="@+id/imageView1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/logo" android:paddingRight="30dp" android:layout_gravity="left" android:layout_weight="0" /> <View android:layout_height="wrap_content" android:id="@+id/view1" android:layout_width="wrap_content" android:layout_weight="1" /> <Button android:id="@+id/categorybutton" android:background="@drawable/button_bg" android:layout_height="match_parent" android:layout_weight="0" android:layout_width="120dp" style="@style/CategoryButtonStyle"/> </LinearLayout> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
請注意示例中使用 "wrap_content"
和 "match_parent"
控制組件尺寸的方法,而不是關注具體的尺寸。此方法可讓佈局正確適應各種屏幕尺寸和屏幕方向。
此視圖在縱向模式和橫向模式下的顯示效果如下所示。請注意,組件的尺寸會自動適應屏幕的高度和寬度:
使用相對佈局
您可以使用 LinearLayout
的嵌套實例並結合 "wrap_content"
和 "match_parent"
尺寸,以便構建相當複雜的佈局。不過,您無法通過 LinearLayout
精確控制子視圖的特殊關係;系統會將 LinearLayout
中的視圖直接並排列出。如果您需要將子視圖排列出各種效果而不是一條直線,通常更合適的解決方法是使用RelativeLayout
,這樣您就可以根據各組件之間的特殊關係指定佈局了。例如,您可以將某個子視圖對齊到屏幕左側,同時將另一個視圖對齊到屏幕右側。
例如:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/label" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Type here:"/> <EditText android:id="@+id/entry" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/label"/> <Button android:id="@+id/ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/entry" android:layout_alignParentRight="true" android:layout_marginLeft="10dp" android:text="OK" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@id/ok" android:layout_alignTop="@id/ok" android:text="Cancel" /> </RelativeLayout>
圖 2 展示的是此佈局在 QVGA 屏幕上的顯示效果。
圖 3 展示的是此佈局在較大屏幕上的顯示效果。
請注意,雖然組件的尺寸有所變化,但它們的空間關係仍會保留,具體由 RelativeLayout.LayoutParams
指定。
使用尺寸限定符
上文所述的靈活佈局或相對佈局可以爲您帶來的優勢就只有這麼多了。雖然這些佈局可以拉伸組件內外的空間以適應各種屏幕,但它們不一定能爲每種屏幕都提供最佳的用戶體驗。因此,您的應用不僅應實施靈活佈局,還應針對各種屏幕配置提供一些備用佈局。要做到這一點,您可以使用配置限定符,這樣就可以在運行時根據當前的設備配置自動選擇合適的資源了(例如根據各種屏幕尺寸選擇不同的佈局)。
例如,很多應用會在較大的屏幕上實施“雙面板”模式(相關應用可能會在一個面板上顯示項目列表,並在另一面板上顯示對應內容)。平板電腦和電視的屏幕已經大到可以同時容納這兩個面板了,但手機屏幕就需要分別顯示。因此,您可以使用以下文件以便實施這些佈局:
res/layout/main.xml
,單面板(默認)佈局:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
res/layout-large/main.xml
,雙面板佈局:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="400dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent" /> </LinearLayout>
請注意第二種佈局名稱目錄中的 large
限定符。系統會在屬於較大屏幕(例如 7 英寸或更大的平板電腦)的設備上選擇此佈局。系統會在較小的屏幕上選擇其他佈局(無限定符)。
使用最小寬度限定符
在版本低於 3.2 的 Android 設備上,開發人員遇到的問題之一是“較大”屏幕的尺寸範圍,該問題會影響戴爾 Streak、早期的 Galaxy Tab 以及大部分 7 英寸平板電腦。即使這些設備的屏幕屬於“較大”的尺寸,但很多應用可能會針對此類別中的各種設備(例如 5 英寸和 7 英寸的設備)顯示不同的佈局。這就是 Android 3.2 版在引入其他限定符的同時引入“最小寬度”限定符的原因。
最小寬度限定符可讓您通過指定某個最小寬度(以 dp 爲單位)來定位屏幕。例如,標準 7 英寸平板電腦的最小寬度爲 600 dp,因此如果您要在此類屏幕上的用戶界面中使用雙面板(但在較小的屏幕上只顯示列表),您可以使用上文中所述的單面板和雙面板這兩種佈局,但您應使用 sw600dp
指明雙面板佈局僅適用於最小寬度爲 600 dp 的屏幕,而不是使用 large
尺寸限定符:
res/layout/main.xml
,單面板(默認)佈局:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
res/layout-sw600dp/main.xml
,雙面板佈局:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="400dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent" /> </LinearLayout>
也就是說,對於最小寬度大於等於 600 dp 的設備,系統會選擇 layout-sw600dp/main.xml
(雙面板)佈局,否則系統就會選擇 layout/main.xml
(單面板)佈局。
但 Android 版本低於 3.2 的設備不支持此技術,原因是這些設備無法將 sw600dp
識別爲尺寸限定符,因此您仍需使用 large
限定符。這樣一來,就會有一個名稱爲 res/layout-large/main.xml
的文件(與 res/layout-sw600dp/main.xml
一樣)。您將在下一教程中瞭解到避免此類佈局文件出現重複的技術。
使用佈局別名
最小寬度限定符僅適用於 Android 3.2 及更高版本。因此,您仍需使用與較低版本兼容的概括尺寸範圍(小、正常、大和特大)。例如,如果您要將用戶界面設計成在手機上顯示單面板,但在 7 英寸平板電腦、電視和其他較大的設備上顯示多面板,請提供以下文件:
res/layout/main.xml:
單面板佈局res/layout-large:
多面板佈局res/layout-sw600dp:
多面板佈局
後兩個文件是相同的,因爲其中一個用於和 Android 3.2 設備匹配,而另一個則是爲使用較低版本 Android 的平板電腦和電視準備的。
要避免平板電腦和電視的文件出現重複(以及由此帶來的維護問題),您可以使用別名文件。例如,您可以定義以下佈局:
res/layout/main.xml
,單面板佈局res/layout/main_twopanes.xml
,雙面板佈局
然後添加這兩個文件:
res/values-large/layout.xml
:<resources> <item name="main" type="layout">@layout/main_twopanes</item> </resources>
res/values-sw600dp/layout.xml
:<resources> <item name="main" type="layout">@layout/main_twopanes</item> </resources>
後兩個文件的內容相同,但它們並未實際定義佈局。它們只是將 main
設置成了 main_twopanes
的別名。由於這些文件包含 large
和 sw600dp
選擇器,因此無論 Android 版本如何,系統都會將這些文件應用到平板電腦和電視上(版本低於 3.2 的平板電腦和電視會匹配 large
,版本低於
3.2 的平板電腦和電視則會匹配 sw600dp
)。
使用屏幕方向限定符
某些佈局會同時支持橫向模式和縱向模式,但您可以通過調整優化其中大部分佈局的效果。在新聞閱讀器示例應用中,每種屏幕尺寸和屏幕方向下的佈局行爲方式如下所示:
- 小屏幕,縱向:單面板,帶徽標
- 小屏幕,橫向:單面板,帶徽標
- 7 英寸平板電腦,縱向:單面板,帶操作欄
- 7 英寸平板電腦,橫向:雙面板,寬,帶操作欄
- 10 英寸平板電腦,縱向:雙面板,窄,帶操作欄
- 10 英寸平板電腦,橫向:雙面板,寬,帶操作欄
- 電視,橫向:雙面板,寬,帶操作欄
因此,這些佈局中的每一種都定義在了 res/layout/
目錄下的某個 XML 文件中。爲了繼續將每個佈局分配給各種屏幕配置,該應用會使用佈局別名將兩者相匹配:
res/layout/onepane.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
res/layout/onepane_with_bar.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:id="@+id/linearLayout1" android:gravity="center" android:layout_height="50dp"> <ImageView android:id="@+id/imageView1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/logo" android:paddingRight="30dp" android:layout_gravity="left" android:layout_weight="0" /> <View android:layout_height="wrap_content" android:id="@+id/view1" android:layout_width="wrap_content" android:layout_weight="1" /> <Button android:id="@+id/categorybutton" android:background="@drawable/button_bg" android:layout_height="match_parent" android:layout_weight="0" android:layout_width="120dp" style="@style/CategoryButtonStyle"/> </LinearLayout> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
res/layout/twopanes.xml
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="400dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent" /> </LinearLayout>
res/layout/twopanes_narrow.xml
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="200dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent" /> </LinearLayout>
既然您已定義了所有可能的佈局,那就只需使用配置限定符將正確的佈局映射到各種配置即可。您現在只需使用佈局別名技術即可做到這一點:
res/values/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/onepane_with_bar</item> <bool name="has_two_panes">false</bool> </resources>
res/values-sw600dp-land/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/twopanes</item> <bool name="has_two_panes">true</bool> </resources>
res/values-sw600dp-port/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/onepane</item> <bool name="has_two_panes">false</bool> </resources>
res/values-large-land/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/twopanes</item> <bool name="has_two_panes">true</bool> </resources>
res/values-large-port/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/twopanes_narrow</item> <bool name="has_two_panes">true</bool> </resources>
使用自動拉伸位圖
支持各種屏幕尺寸通常意味着您的圖片資源還必須能適應各種尺寸。例如,無論要應用到什麼形狀的按鈕上,按鈕背景都必須能適應。
如果在可以更改尺寸的組件上使用了簡單的圖片,您很快就會發現顯示效果多少有些不太理想,因爲系統會在運行時平均地拉伸或收縮您的圖片。解決方法爲使用自動拉伸位圖,這是一種格式特殊的 PNG 文件,其中會指明可以拉伸以及不可以拉伸的區域。
因此,如果設計的是用於尺寸可變的組件上的位圖,請務必使用自動拉伸技術。要將某個位圖轉換成自動拉伸位圖,您可以先準備好普通圖片(圖 4,放大了 4 倍以便清楚顯示)。
然後通過 SDK 的 draw9patch
實用工具(位於 tools/
目錄中)運行該圖片,您可以在該工具中繪製像素以標出要拉伸的區域以及左側和頂部的邊界。您還可以沿右側和底部邊界繪製像素以標出用於放置內容的區域,具體如圖 5 所示。
請注意沿邊界顯示的黑色像素。頂部和左側邊界上的像素用於指定可以拉伸的圖片區域,右側和底部邊界上的像素則用於指定放置內容的區域。
另請注意 .9.png
的擴展名。您必須使用此擴展名,因爲系統框架需要通過此擴展名確定相關圖片是自動拉伸位圖,而不是普通 PNG 圖片。
如果您將此背景應用到某個組件(通過設置 android:background="@drawable/button"
),系統框架就會正確拉伸圖片以適應按鈕的尺寸,具體如圖 6 中的各種尺寸所示。