W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
編寫:riverfeng - 原文:http://developer.android.com/training/multiscreen/screensizes.html
這節(jié)課教你如何通過以下幾種方式支持多屏幕:
1、確保你的布局能自適應(yīng)屏幕
2、根據(jù)你的屏幕配置提供合適的UI布局
3、確保正確的布局適合正確的屏幕。
4、提供縮放正確的位圖(bitmap)
為了確保你的布局能靈活的適應(yīng)不同的屏幕尺寸,針對一些view組件,你應(yīng)該使用wrap_content和match_parent來設(shè)置他們的寬和高。如果你使用了wrap_content,view的寬和高會被設(shè)置為該view所包含的內(nèi)容的大小值。如果是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來指定組件尺寸而不是使用固定的尺寸。這樣就能使你的布局正確的適配不同的屏幕尺寸和屏幕方向(這里的配置主要是指屏幕的橫豎屏切換)。
例如,下圖演示的就是該布局在豎屏和橫屏模式下的效果,注意組件的尺寸是自動適應(yīng)寬和高的。
圖1:News Reader示例app(左邊豎屏,右邊橫屏)。
你可以使用LinearLayout以及wrap_content和match_parent組合來構(gòu)建復(fù)雜的布局,但是LinearLayout卻不允許你精準的控制它子view的關(guān)系,子view在LinearLayout中只能簡單一個接一個的排成行。如果你需要你的子view不只是簡簡單單的排成行的排列,更好的方法是使用RelativeLayout,它允許你指定你布局中控件與控件之間的關(guān)系,比如,你可以指定一個子view在左邊,另一個則在屏幕的右邊。
<?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:WSVGA(大尺寸屏幕)屏幕下截圖
注意:盡管組件的尺寸發(fā)生了變化,但是它的子view之間的空間關(guān)系還是通過RelativeLayout.LayoutParams已經(jīng)指定好了。
(譯者注:這里的限定詞主要是指在編寫布局文件時,將布局文件放在加上類似large,sw600dp等這樣限定詞的文件夾中,以此來告訴系統(tǒng)根據(jù)屏幕選擇對應(yīng)的布局文件,比如下面例子的layout-large文件夾)
從上一節(jié)的學(xué)習(xí)里程中,我們知道如何編寫靈活的布局或者相對布局,它們都能通過拉伸或者填充控件來適應(yīng)不同的屏幕,但是它們卻不能為每個不同屏幕尺寸提供最好的用戶體驗。因此,你的應(yīng)用不應(yīng)該只是實現(xiàn)靈活的布局,同時也應(yīng)該為不同的屏幕配置提供幾種不同的布局方式。你可以通過配置限定(configuration qualifiers)來做這件事情,它能在運行時根據(jù)你當(dāng)前設(shè)備的配置(比如不同的屏幕尺寸設(shè)計了不同的布局)來選擇合適的布局資源。
比如,很多應(yīng)用都為大屏幕實現(xiàn)了“兩個窗格”模式(應(yīng)用可能在一個窗格中實現(xiàn)一個list的item,另外一個則實現(xiàn)list的content),平板和電視都是大到能在一個屏幕上適應(yīng)兩個窗格,但是手機屏幕卻只能分別顯示。所以,如果你想實現(xiàn)這些布局,你就需要以下文件:
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>
注意第二個布局文件的目錄名字“l(fā)arge qualifier”,在大尺寸的設(shè)備屏幕時(比如7寸平板或者其他大屏幕的設(shè)備)就會選擇該布局文件,而其他比較小的設(shè)備則會選擇沒有限定詞的另一個布局(也就是第一個布局文件)。
在Android 3.2之前,開發(fā)者還有一個困難,那就是Android設(shè)備的“l(fā)arge”屏幕尺寸,其中包括Dell Streak(設(shè)備名稱),老版Galaxy Tab和一般的7寸平板,有很多的應(yīng)用都想針對這些不同的設(shè)備(比如5和7寸的設(shè)備)定義不同的布局,但是這些設(shè)備都被定義為了large尺寸屏幕。也是因為這個,所以Android在3.2的時候開始使用最小寬度限定詞。
最小寬度限定詞允許你根據(jù)設(shè)備的最小寬度(dp單位)來指定不同布局。比如,傳統(tǒng)的7寸平板最小寬度為600dp,如果你希望你的UI能夠在這樣的屏幕上顯示兩個窗格(不是一個窗格顯示在小屏幕上),你可以使用上節(jié)中提到的使用同樣的兩個布局文件。不同的是,使用sw600來指定兩個方框的布局使用在最小寬度為600dp的設(shè)備上。
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>
這樣意味著當(dāng)你的設(shè)備的最小寬度等于600dp或者更大時,系統(tǒng)選擇layout-sw600dp/main.xml(兩個窗格)的布局,而小一點的屏幕則會選擇layout/main.xml(單個窗格)的布局。 然而,在3.2之前的設(shè)備上,這樣做并不是很好的選擇。因為3.2之前還沒有將sw600dp作為一個限定詞出現(xiàn),所以,你還是需要使用large限定詞來做。因此,你還是應(yīng)該要有一個布局文件名為res/layout-large/main.xml,和res/layout-sw600dp/main.xml一樣。在下一節(jié)中,你將學(xué)到如何避免像這樣出現(xiàn)重復(fù)的布局文件。
最小寬度限定詞只能在android3.2或者更高的版本上使用。因此,你還是需要使用抽象尺寸(small,normal,large,xlarge)來兼容以前的版本。比如,你想要將你的UI設(shè)計為在手機上只顯示一個方框的布局,而在7寸平板或電視,或者其他大屏幕設(shè)備上顯示多個方框的布局,你可能得提供這些文件:
res/layout/main.xml:單個窗格布局
res/layout-large:多個窗格布局
res/layout-sw600dp:多個窗格布局
最后兩個文件都是一樣的,因為其中一個將會適配Android3.2的設(shè)備,而另外一個則會適配其他Android低版本的平板或者電視。 為了避免這些重復(fù)的文件(維護讓人感覺頭痛就是因為這個),你可以使用別名文件。比如,你可以定義如下布局:
然后添加這兩個文件:
<resources>
<item name="main" type="layout">@layout/main_twopanes</item>
</resources>
<resources>
<item name="main" type="layout">@layout/main_twopanes</item>
</resources>
最后兩個文件擁有相同的內(nèi)容,但它們并沒有真正意義上的定義布局。它們只是將main_twopanes設(shè)置成為了別名main,它們分別處在large和sw600dp選擇器中,所以它們能適配Android任何版本的平板和電視(在3.2之前平板和電視可以直接匹配large,而3.2或者以上的則匹配sw600dp)。有一些布局不管是在橫向還是縱向的屏幕配置中都能顯示的非常好,但是更多的時候,適當(dāng)?shù)恼{(diào)整一下會更好。在News Reader應(yīng)用例子中,以下是布局在不同屏幕尺寸和方向的行為:
這些每個布局都會在res/layout目錄下定義一個xml文件,如此,應(yīng)用就能根據(jù)屏幕配置的變化根據(jù)別名匹配到對應(yīng)的布局來適應(yīng)屏幕。
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>
現(xiàn)在所有可能的布局我們都已經(jīng)定義了,唯一剩下的問題是使用方向限定詞來匹配對應(yīng)的布局給屏幕。這時候,你就可以使用布局別名的功能了:
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>
支持不同的屏幕尺寸同時也意味著你的圖片資源也必須能兼容不同的屏幕尺寸。比如,一個button的背景圖片就必須要適應(yīng)該button的各種形狀。
如果你在使用組件時可以改變圖片的大小,你很快就會發(fā)現(xiàn)這是一個不明確的選擇。因為運行的時候,圖片會被拉伸或者壓縮(這樣容易造成圖片失真)。避免這種情況的解決方案就是使用點9圖片,這是一種能夠指定哪些區(qū)域能夠或者不能夠拉伸的特殊png文件。
因此,在設(shè)計的圖片需要與組件一起變大變小時,一定要使用點9.若要將位圖轉(zhuǎn)換為點9,你可以用一個普通的圖片開始(下圖,是在4倍變焦情況下的圖片顯示)。
你可以通過sdk中的draw9patch程序(位于tools/directory目錄下)來畫點9圖片。通過沿左側(cè)和頂部邊框繪制像素來標(biāo)記應(yīng)該被拉伸的區(qū)域。也可以通過沿右側(cè)和底部邊界繪制像素來標(biāo)記。就像下圖所示一樣:
請注意,上圖沿邊界的黑色像素。在頂部邊框和左邊框的那些表明圖像的可拉伸區(qū)域,右邊和底部邊框則表示內(nèi)容應(yīng)該放置的地方。
此外,注意.9.png這個格式,你也必須用這個格式,因為系統(tǒng)會檢測這是一個點9圖片而不是一個普通PNG圖片。
當(dāng)你將這個應(yīng)用到組件的背景的時候(通過設(shè)置android:background="@drawable/button"),android框架會自動正確的拉伸圖像以適應(yīng)按鈕的大小,下圖就是各種尺寸中的顯示效果:
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: