http://blog.csdn.net/a501934002/article/details/52451658
http://blog.csdn.net/u013560890/article/details/47061879
http://mobile.51cto.com/android-245644.htm
注:需要注意的就是PAD有橫屏和豎屏之分,要分別做適配。
本文將告訴你如何讓你的應用程序支持各種不同屏幕大小,主要通過以下幾種辦法:
- 讓你的佈局能充分的自適應屏幕
- 根據屏幕的配置來加載合適的UI佈局
- 確保正確的佈局應用在正確的設備屏幕上
- 提供可以根據屏幕大小自動伸縮的圖片
使用 "wrap_content" 和 "match_parent"
爲了確保你的佈局能夠自適應各種不同屏幕大小,你應該在佈局的視圖中使用"wrap_content"和"match_parent"來確定它的寬和高。如果你使用了"wrap_content",相應視圖的寬和高就會被設定成剛好能夠包含視圖中內容的最小值。而如果你使用了"match_parent"(在Android 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>
下圖是這個佈局分別在豎屏和橫屏時顯示的結果,注意控件的寬和高是根據屏幕自適應的。
使用RelativeLayout
通過多層嵌套LinearLayout和組合使用"wrap_content"和"match_parent"已經可以構建出足夠複雜的佈局。但是LinearLayout無法允許你準確地控制子視圖之前的位置關係,所有LinearLayout中的子視圖只能簡單的一個挨着一個地排列。如果你需要讓子視圖能夠有更多的排列方式,而不是簡單地排成一行或一列,使用RelativeLayout將會是更好的解決方案。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>
下圖展示了這個佈局在QVGA屏幕上顯示的結果。
下圖展示了這個佈局在一個更大的屏幕上顯示的結果。
可以注意到,即使屏幕的大小改變,視圖之前的相對位置都沒有改變。
使用Size限定符
雖然使用以上幾種方式可以解決屏幕適配性的問題,但是那些通過伸縮控件來適應各種不同屏幕大小的佈局,未必就是提供了最好的用戶體驗。你的應用程序應該不僅僅實現了可自適應的佈局,還應該提供一些方案根據屏幕的配置來加載不同的佈局,可以通過配置限定符(configuration qualifiers)來實現。配置限定符允許程序在運行時根據當前設備的配置自動加載合適的資源(比如爲不同尺寸屏幕設計不同的佈局)。
現在有很多的應用程序爲了支持大屏設備,都會實現“two pane”模式(程序會在左側的面板上展示一個包含子項的List,在右側面板上展示內容)。平板和電視設備的屏幕都很大,足夠同時顯示兩個面板,而手機屏幕一次只能顯示一個面板,兩個面板需要分開顯示。所以,爲了實現這種佈局,你可能需要以下文件:
res/layout/main.xml,single-pane(默認)佈局:
- <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>
- <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寸以上的平板)會自動加載此佈局,而小屏設備會加載另一個默認的佈局。
使用Smallest-width限定符
使用Size限定符有一個問題會讓很多程序員感到頭疼,large到底是指多大呢?很多應用程序都希望能夠更自由地爲不同屏幕設備加載不同的佈局,不管它們是不是被系統認定爲"large"。這就是Android爲什麼在3.2以後引入了"Smallest-width"限定符。
Smallest-width限定符允許你設定一個具體的最小值(以dp爲單位)來指定屏幕。例如,7寸的平板最小寬度是600dp,所以如果你想讓你的UI在這種屏幕上顯示two pane,在更小的屏幕上顯示single pane,你可以使用sw600dp來表示你想在600dp以上寬度的屏幕上使用two pane模式。
res/layout/main.xml,single-pane(默認)佈局:
- <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>
- <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>
然而,使用早於Android 3.2系統的設備將無法識別sw600dp這個限定符,所以你還是同時需要使用large限定符。這樣你就需要在res/layout-large和res/layout-sw600dp目錄下都添加一個相同的main.xml。下節你將會看到如何避免重複定義這種佈局的技巧。
使用佈局別名
Smallest-width限定符僅在Android 3.2及之後的系統中有效。因而,你也需要同時使用Size限定符(small, normal, large和xlarge)來兼容更早的系統。例如,你想手機上顯示single-pane界面,而在7寸平板和更大屏的設備上顯示multi-pane界面,你需要提供以下文件:
- res/layout/main.xml: single-pane佈局
- res/layout-large: multi-pane佈局
- res/layout-sw600dp: multi-pane佈局
最後的兩個文件是完全相同的,爲了要解決這種重複,你需要使用別名技巧。例如,你可以定義以下佈局:
- res/layout/main.xml, single-pane佈局
- res/layout/main_twopanes.xml, two-pane佈局
加入以下兩個文件:
res/values-large/layout.xml:
- <resources>
- <item name="main" type="layout">@layout/main_twopanes</item>
- </resources>
- <resources>
- <item name="main" type="layout">@layout/main_twopanes</item>
- </resources>
最後兩個文件有着相同的內容,但是它們並沒有真正去定義佈局,它們僅僅只是給main定義了一個別名main_twopanes。這樣兩個layout.xml都只是引用了@layout/main_twopanes,就避免了重複定義佈局文件的情況。
使用Orientation限定符
有些佈局會在橫屏和豎屏的情況下都顯示的很好,但是多數情況下這些佈局都可以再調整的。在News Reader示例程序中,佈局在不同屏幕尺寸和不同屏幕方向中是這樣顯示的:
- 小屏幕, 豎屏: 單面板, 顯示logo
- 小屏幕, 橫屏: 單面板, 顯示logo
- 7寸平板, 豎屏: 單面板, 顯示action bar
- 7寸平板, 橫屏: 雙面板, 寬, 顯示action bar
- 10寸平板, 豎屏: 雙面板, 窄, 顯示action bar
- 10寸平板, 橫屏: 雙面板, 寬, 顯示action bar
- 電視, 橫屏: 雙面板, 寬, 顯示action bar
所有這些佈局都是定義在 res/layout/ 這個目錄下,爲了要讓設備根據屏幕配置來加載正確的佈局,程序需要使用佈局別名來實現。
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>
- <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>
- <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>
- <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>
- <resources>
- <item name="main_layout" type="layout">@layout/twopanes</item>
- <bool name="has_two_panes">true</bool>
- </resources>
- <resources>
- <item name="main_layout" type="layout">@layout/onepane</item>
- <bool name="has_two_panes">false</bool>
- </resources>
- <resources>
- <item name="main_layout" type="layout">@layout/twopanes</item>
- <bool name="has_two_panes">true</bool>
- </resources>
- <resources>
- <item name="main_layout" type="layout">@layout/twopanes_narrow</item>
- <bool name="has_two_panes">true</bool>
- </resources>