問題
Android 設(shè)備各種屏幕尺寸和形狀,如何做好適配?
你還在為開發(fā)中頻繁切換環(huán)境打包而煩惱嗎?快來試試 Environment Switcher 吧!使用它可以在app運(yùn)行時一鍵切換環(huán)境,而且還支持其他貼心小功能,有了它媽媽再也不用擔(dān)心頻繁環(huán)境切換了。https://github.com/CodeXiaoMai/EnvironmentSwitcher
解決思路和辦法
- Android 系統(tǒng)定義了兩種常規(guī)屬性對設(shè)備屏幕進(jìn)行分類:大小和密度。
- 為了優(yōu)化應(yīng)用程序的外觀,以適應(yīng)不同的屏幕尺寸和密度,可以添加一些替代資源(布局和圖片)。
因此對不同屏幕尺寸、形狀以及密度的適配,其實(shí)就是對布局和圖片的適配。
布局適配
要優(yōu)化不同屏幕尺寸的用戶體驗(yàn),應(yīng)該為要支持的每個屏幕尺寸創(chuàng)建一個獨(dú)特的布局XML文件。每個布局應(yīng)該保存到相應(yīng)的資源目錄中,命名為 - <screen_size>后綴。
Android 3.2 之前和之后的方案是不一樣的。
Android 3.2 -
系統(tǒng)定義了四種常用大小:small, normal, large, xlarge
和四種常用密度:low (ldpi), medium (mdpi 默認(rèn)), high (hdpi), extra high (xhdpi)
就像適配不同的語言一樣,要聲明用于不同屏幕的布局和位圖,必須將這些替代資源放在不同的目錄中。
還要注意,屏幕方向(橫向或縱向)也被認(rèn)為是屏幕尺寸的變化,所以許多應(yīng)用程序應(yīng)該修改布局,以優(yōu)化每個方向的用戶體驗(yàn)。
例如,大型屏幕的獨(dú)特布局應(yīng)該保存在 res/layout-large/ 下。
Android會自動縮放布局,以適應(yīng)屏幕。因此,不同屏幕尺寸的布局不需要擔(dān)心UI元素的絕對大小,而需要重點(diǎn)關(guān)注的是影響用戶體驗(yàn)的布局結(jié)構(gòu)(例如相對于兄弟視圖的重要視圖的大小或位置)。
例如,在項(xiàng)目中創(chuàng)建 默認(rèn)布局 和 支持大屏幕 的替代布局。
MyProject/
res/
layout/
main.xml
layout-large/
main.xml
如上面代碼所示,文件名必須完全相同,但內(nèi)容不同,才能為相應(yīng)的屏幕尺寸提供優(yōu)化的UI。
系統(tǒng)會根據(jù)運(yùn)行應(yīng)用程序的設(shè)備的屏幕大小從相應(yīng)的布局目錄加載布局文件。有關(guān)Android選擇適當(dāng)資源的更多信息,請參閱“提供資源”指南。
如果應(yīng)用支持橫豎屏切換,還應(yīng)提供橫屏的布局,這里是一個具有用于橫向定向的替代布局的項(xiàng)目
MyProject/
res/
layout/
main.xml
layout-land/
main.xml
默認(rèn)情況下,layout/main.xml 文件用于縱向。
如果你想提供一個支持 大屏幕 和 橫屏 的特殊布局,你需要同時使用 large 和 land 限定詞:
MyProject/
res/
layout/ # default (portrait)
main.xml
layout-land/ # landscape
main.xml
layout-large/ # large (portrait)
main.xml
layout-large-land/ # large landscape
main.xml
Android 3.2 +
在Android 3.2 之前,其中一個困難是“龐大”的屏幕尺寸容器,其中囊括了 Dell Streak、原版 Galaxy Tab 以及常規(guī) 7 英寸平板電腦。 不過,盡管這些設(shè)備都被視為“大”屏設(shè)備,許多應(yīng)用可能仍需要為此類別中的不同設(shè)備(如為 5 英寸和 7 英寸設(shè)備)顯示不同的布局。 正因如此,Android 在 Android 3.2 中引入了“最小寬度”限定符。
最小寬度 限定符允許您將目標(biāo)鎖定在具有特定最小寬度(單位:dp)的屏幕。 例如,典型的 7 英寸平板電腦最小寬度為 600dp,因此,如果您希望您的 UI 在這些屏幕上顯示兩個窗格(但在較小屏幕上顯示單個列表),您同樣可以為單窗格布局和雙窗格布局使用兩種布局,但不使用 large 尺寸限定符,而是使用 sw600dp 為最小寬度是 600dp 的屏幕指定雙窗格布局:
- res/layout/main.xml,單窗格(默認(rèn))布局:
<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>
這意味著,最小寬度大于或等于 600dp 的設(shè)備將選擇 layout-sw600dp/main.xml(雙窗格)布局,而屏幕較小的設(shè)備將選擇 layout/main.xml(單窗格)布局。
不過,這種方法在低于 3.2 版本的設(shè)備上不太奏效,因?yàn)樗鼈儫o法將 sw600dp 識別為尺寸限定符,所以您仍需使用 large 限定符。因此,您應(yīng)該建立一個與 res/layout-sw600dp/main.xml 完全相同的、名為 res/layout-large/main.xml 的文件。下文介紹的技巧可讓您避免因此而產(chǎn)生重復(fù)的布局文件。
使用布局別名
如果您的應(yīng)用的 minSdkVersion 大于等于 3.2,可以跳過此部分。
最小寬度限定符僅在 Android 3.2 及更高版本上提供。因此,您仍應(yīng)使用兼容早期版本的抽象尺寸容器(小、正常、大和超大)。 例如,如果您想讓自己設(shè)計的 UI 在手機(jī)上顯示單窗格 UI,但在 7 英寸平板電腦、TV 及其他大屏設(shè)備上顯示多窗格 UI,則需要提供下列文件:
- res/layout/main.xml: 單窗格布局
- res/layout-large: 多窗格布局
- res/layout-sw600dp: 多窗格布局
后兩個文件雖然名字不同,但內(nèi)容完全相同,因?yàn)槠渲幸粋€將由 Android 3.2 + 設(shè)備匹配,另一個是為了照顧使用早期版本 Android 的平板電腦和 TV 的需要。
為避免為平板電腦和 TV 產(chǎn)生相同的重復(fù)文件(以及由此帶來的維護(hù)難題),您可以使用別名文件。 例如,您可以定義下列布局:
- 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>
后兩個文件內(nèi)容完全相同,但它們實(shí)際上并未定義布局, 而只是將 main 設(shè)置為 main_twopanes 的別名。由于這些文件具有 large 和 sw600dp 選擇器,因此它們適用于任何 Android 版本的平板電腦和電視(低于 3.2 版本的平板電腦和電視匹配 large,高于 3.2 版本者將匹配 sw600dp)。
創(chuàng)建不同的位圖
我們應(yīng)該始終提供適當(dāng)縮放到每個通用密度設(shè)備的位圖資源:低,中,高和超高密度。這有助于App在所有屏幕密度上實(shí)現(xiàn)良好的圖形質(zhì)量和性能。
要生成這些圖像,應(yīng)該以矢量格式從原始資源開始,并使用以下尺寸比例為每個密度生成圖片:
- xhdpi: 2.0
- hdpi: 1.5
- mdpi: 1.0 (baseline)
- ldpi: 0.75
例如:如果為xhdpi設(shè)備生成200x200圖片,則應(yīng)為hdpi生成150x150,mdpi為100x100,ldpi 為75x75的的相同資源。
然后,將文件放在適當(dāng)?shù)膁rawable資源目錄中:
MyProject/
res/
drawable-xhdpi/
awesomeimage.png
drawable-hdpi/
awesomeimage.png
drawable-mdpi/
awesomeimage.png
drawable-ldpi/
awesomeimage.png
當(dāng)在代碼中引用@drawable/awesomeimage時,系統(tǒng)會根據(jù)當(dāng)前設(shè)備的屏幕密度選擇適當(dāng)?shù)奈粓D。
低密度(ldpi)資源并不總是必需的。如果提供了hdpi資源時,系統(tǒng)將其縮小一半以適應(yīng)ldpi屏幕。
使用九宮格位圖
支持不同屏幕尺寸通常意味著您的圖像資源也必須能夠適應(yīng)不同的尺寸。 例如,按鈕背景必須能夠適應(yīng)其所應(yīng)用到的任何一種按鈕形狀。
如果您在可能改變尺寸的組件上使用簡單圖像,您很快會發(fā)現(xiàn)效果有些差強(qiáng)人意,因?yàn)檫\(yùn)行組件會均勻地拉伸或縮小您的圖像。 解決方案是使用九宮格位圖,這種特殊格式的 PNG 文件會指示哪些區(qū)域可以拉伸,哪些區(qū)域不可以拉伸。
因此,在設(shè)計將用于尺寸可變組件的位圖時,請一律使用九宮格位圖。