Android 可在各種具有不同屏幕尺寸和密度的設(shè)備上運(yùn)行,實(shí)際開發(fā)中常常會(huì)被要求:一個(gè)app能在不同型號(hào)手機(jī)上使用,同時(shí)保證不會(huì)出現(xiàn)UI顯示不全、UI顯示失真等情況。本文主要介紹了Android常見的屏幕適配問題。
一、屏幕適配概覽
本節(jié)概述 Android 對(duì)多種屏幕的支持,
包括:術(shù)語和概念、支持的屏幕范圍、密度獨(dú)立性
術(shù)語和概念
屏幕尺寸 :
????按屏幕對(duì)角測(cè)量的實(shí)際物理尺寸。
????為簡(jiǎn)便起見,Android 將所有實(shí)際屏幕尺寸分組為四種通用尺寸:小、 正常、大和超大。
屏幕密度 :
????屏幕物理區(qū)域中的像素量;通常稱為 dpi(每英寸 點(diǎn)數(shù))。例如, 與“正?!被颉案摺泵芏绕聊幌啾龋暗汀泵芏绕聊辉诮o定物理區(qū)域的像素較少。
????為簡(jiǎn)便起見,Android 將所有屏幕密度分組為六種通用密度: 低、中、高、超高、超超高和超超超高。
方向:
????從用戶視角看屏幕的方向,即橫屏還是 豎屏,分別表示屏幕的縱橫比是寬還是高。請(qǐng)注意, 不僅不同的設(shè)備默認(rèn)以不同的方向操作,而且 方向在運(yùn)行時(shí)可隨著用戶旋轉(zhuǎn)設(shè)備而改變。
分辨率:
????屏幕上物理像素的總數(shù)。添加對(duì)多種屏幕的支持時(shí), 應(yīng)用不會(huì)直接使用分辨率;而只應(yīng)關(guān)注通用尺寸和密度組指定的屏幕 尺寸及密度。
密度無關(guān)像素 (dp):
????在定義 UI 布局時(shí)應(yīng)使用的虛擬像素單位,用于以密度無關(guān)方式表示布局維度 或位置。
????密度無關(guān)像素等于 160 dpi 屏幕上的一個(gè)物理像素,這是 系統(tǒng)為“中”密度屏幕假設(shè)的基線密度。在運(yùn)行時(shí),系統(tǒng) 根據(jù)使用中屏幕的實(shí)際密度按需要以透明方式處理 dp 單位的任何縮放 。dp 單位轉(zhuǎn)換為屏幕像素很簡(jiǎn)單: px = dp * (dpi / 160)。 例如,在 240 dpi 屏幕上,1 dp 等于 1.5 物理像素。在定義應(yīng)用的 UI 時(shí)應(yīng)始終使用 dp 單位 ,以確保在不同密度的屏幕上正常顯示 UI。
支持的屏幕范圍
從 Android 1.6(API 級(jí)別 4)開始,Android 支持多種屏幕尺寸和密度,反映設(shè)備可能具有的多種不同屏幕配置。
為簡(jiǎn)化您為多種屏幕設(shè)計(jì)用戶界面的方式,Android 將實(shí)際屏幕尺寸和密度的范圍 分為:
- 四種通用尺寸:小、正常、 大 和超大
- 從 Android 3.2(API 級(jí)別 13)開始,這些尺寸組 已棄用,
2.六種通用的密度: - ldpi(低)~120dpi
- mdpi(中)~160dpi
- hdpi(高)~240dpi
- xhdpi(超高)~320dpi
- xxhdpi(超超高)~480dpi
- xxxhdpi(超超超高)~640dpi(別笑 google就是這么定義的-.-//)
- 從 Android 3.2(API 級(jí)別 13)開始,這些尺寸組 已棄用,
????通用的尺寸和密度按照基線配置(即正常尺寸和 mdpi(中)密度)排列。每種通用的尺寸和密度都涵蓋一個(gè)實(shí)際屏幕尺寸和密度范圍。例如, 兩部都報(bào)告正常屏幕尺寸的設(shè)備在手動(dòng)測(cè)量時(shí),實(shí)際屏幕尺寸和 高寬比可能略有不同。類似地,對(duì)于兩臺(tái)報(bào)告 hdpi 屏幕密度的設(shè)備,其實(shí)際像素密度可能略有不同。 Android 將這些差異抽象概括到應(yīng)用,使您可以提供為通用尺寸和密度設(shè)計(jì)的 UI,讓系統(tǒng)按需要處理任何最終調(diào)整。
????圖 1 說明不同的尺寸和密度如何粗略歸類為不同的尺寸 和密度組。

密度獨(dú)立性
????應(yīng)用顯示在密度不同的屏幕上時(shí),如果它保持用戶界面元素的物理尺寸(從 用戶的視角),便可實(shí)現(xiàn)“密度獨(dú)立性”
????保持密度獨(dú)立性很重要,因?yàn)槿绻麤]有此功能,UI 元素(例如 按鈕)在低密度屏幕上看起來較大,在高密度屏幕上看起來較小。這些 密度相關(guān)的大小變化可能給應(yīng)用布局和易用性帶來問題。
????圖 2 和 3 分別顯示了應(yīng)用不提供密度獨(dú)立性和 提供密度獨(dú)立性時(shí)的差異。


Android 系統(tǒng)可幫助您的應(yīng)用以兩種方式實(shí)現(xiàn)密度獨(dú)立性:
- 系統(tǒng)根據(jù)當(dāng)前屏幕密度擴(kuò)展 dp 單位數(shù)
- 系統(tǒng)在必要時(shí)可根據(jù)當(dāng)前屏幕 密度將可繪制對(duì)象資源擴(kuò)展到適當(dāng)?shù)拇笮?/li>
在圖 2 中,文本視圖和位圖可繪制對(duì)象具有以像素(px 單位)指定的尺寸,因此視圖的物理尺寸在低密度屏幕上更大,在高密度 屏幕上更小。這是因?yàn)椋m然實(shí)際屏幕尺寸可能相同,但高密度屏幕 的每英寸像素更多(同樣多的像素在一個(gè)更小的區(qū)域內(nèi))。在圖 3 中,布局 尺寸以密度獨(dú)立的像素(dp 單位)指定。由于 密度獨(dú)立像素的基線是中密度屏幕,因此具有中密度屏幕的設(shè)備看起來 與圖 2 一樣。但對(duì)于低密度和高密度屏幕,系統(tǒng) 將分別增加和減少密度獨(dú)立像素值,以適應(yīng) 屏幕。
????大多數(shù)情況下,確保應(yīng)用中的屏幕獨(dú)立性很簡(jiǎn)單,只需以適當(dāng)?shù)拿芏泉?dú)立像素(dp 單位)或 "wrap_content" 指定所有 布局尺寸值。系統(tǒng)然后根據(jù)適用于當(dāng)前屏幕密度的縮放比例適當(dāng)?shù)乜s放位圖可繪制對(duì)象,以 適當(dāng)?shù)拇笮★@示。
????但位圖縮放可能導(dǎo)致模糊或像素化位圖,您或許已經(jīng)在上面的屏幕截圖中 發(fā)現(xiàn)了這些問題。為避免這些偽影,應(yīng)為 不同的密度提供替代的位圖資源。例如,應(yīng)為高密度 屏幕提供分辨率較高的位圖,然后系統(tǒng)對(duì)中密度 屏幕將使用這些位圖,而無需調(diào)整位圖大小。下一節(jié)詳細(xì)說明如何為 不同的屏幕配置提供備用資源。
二、如何支持多種屏幕
????Android 支持多種屏幕的基礎(chǔ)是它能夠管理針對(duì)當(dāng)前屏幕配置 以適當(dāng)方式渲染應(yīng)用的布局和位圖 可繪制對(duì)象。系統(tǒng)可處理大多數(shù)工作,通過適當(dāng)?shù)?縮放布局以適應(yīng)屏幕尺寸/密度和根據(jù)屏幕密度縮放位圖可繪制對(duì)象 ,在每種屏幕配置中渲染您的應(yīng)用。但是,為了更適當(dāng)?shù)靥幚聿煌钠聊慌渲?,還應(yīng)該:
-
在清單中顯式聲明您的應(yīng)用 支持哪些屏幕尺寸
要聲明應(yīng)用支持的屏幕尺寸,應(yīng)在清單文件中包含<supports-screens>元素。
<supports-screens android:resizeable=["true"| "false"]
android:smallScreens=["true" | "false"]
android:normalScreens=["true" | "false"]
android:largeScreens=["true" | "false"]
android:xlargeScreens=["true" | "false"]
android:anyDensity=["true" | "false"]
android:requiresSmallestWidthDp="integer"
android:compatibleWidthLimitDp="integer"
android:largestWidthLimitDp="integer"/>
為不同屏幕尺寸提供不同的布局
默認(rèn)情況下,Android 會(huì)調(diào)整應(yīng)用布局的大小以適應(yīng)當(dāng)前設(shè)備屏幕。大多數(shù) 情況下效果很好。但有時(shí) UI 可能看起來不太好,需要針對(duì) 不同的屏幕尺寸進(jìn)行調(diào)整。例如,在較大屏幕上,您可能要調(diào)整 某些元素的位置和大小,以利用其他屏幕空間,或者在較小屏幕上, 可能需要調(diào)整大小以使所有內(nèi)容納入屏幕。
使用 sw<N>dp 配置限定符來定義布局資源 可用的最小寬度。例如,如果多窗格平板電腦布局 需要至少 600dp 的屏幕寬度,應(yīng)將其放在 layout-sw600dp/ 中。為不同屏幕密度提供不同的位圖可繪制對(duì)象
默認(rèn)情況下,Android 會(huì)縮放位圖可繪制對(duì)象(.png、.jpg 和 .gif 文件)和九宮格可繪制對(duì)象(.9.png 文件),使它們以適當(dāng)?shù)?物理尺寸顯示在每部設(shè)備上。例如,如果您的應(yīng)用只為 基線中密度屏幕 (mdpi) 提供位圖可繪制對(duì)象,則在高密度 屏幕上會(huì)增大位圖,在低密度屏幕上會(huì)縮小位圖。這種縮放可能在 位圖中造成偽影。為確保位圖的最佳顯示效果,應(yīng)針對(duì) 不同屏幕密度加入不同分辨率的替代版本。
可用于密度特定資源的配置限定符(在下面詳述) 包括ldpi(低)、mdpi(中)、hdpi(高)、xhdpi(超高)、xxhdpi(超超高)和xxxhdpi(超超超高)。例如,高密度屏幕的位圖應(yīng)使用drawable-hdpi/。
注:將您的所有啟動(dòng)器圖標(biāo)放在 res/mipmap-[density]/ 文件夾中,而非 res/drawable-[density]/ 文件夾中,僅當(dāng)要在 xxhdpi 設(shè)備上提供比正常位圖大的啟動(dòng)器圖標(biāo)時(shí)才需要提供 mipmap-xxxhdpi 限定符。無需為所有應(yīng)用的圖像提供 xxxhdpi 資源。
在運(yùn)行時(shí),系統(tǒng)通過 以下程序確保任何給定資源在當(dāng)前屏幕上都能保持盡可能最佳的顯示效果:
-
系統(tǒng)使用適當(dāng)?shù)膫溆觅Y源
根據(jù)當(dāng)前屏幕的尺寸和密度,系統(tǒng)將使用您的應(yīng)用中提供的任何尺寸和 密度特定資源。例如,如果設(shè)備有 高密度屏幕,并且應(yīng)用請(qǐng)求可繪制對(duì)象資源,系統(tǒng)將查找 與設(shè)備配置最匹配的可繪制對(duì)象資源目錄。根據(jù)可用的其他 備用資源,包含 hdpi 限定符(例如 drawable-hdpi/)的資源目錄可能是最佳匹配項(xiàng),因此系統(tǒng)將使用此 目錄中的可繪制對(duì)象資源。 -
如果沒有匹配的資源,系統(tǒng)將使用默認(rèn)資源,并按需要向上 或向下擴(kuò)展,以匹配當(dāng)前的屏幕尺寸和密度。
“默認(rèn)”資源是指未標(biāo)記配置限定符的資源。例如,drawable/ 中的資源是默認(rèn)可繪制資源。 系統(tǒng)假設(shè)默認(rèn)資源設(shè)計(jì)用于基線屏幕尺寸和密度,即 正常屏幕尺寸和中密度。 因此,系統(tǒng)對(duì)于高密度屏幕向上擴(kuò)展默認(rèn)密度 資源,對(duì)于低密度屏幕向下擴(kuò)展。
當(dāng)系統(tǒng)查找密度特定的資源但在 密度特定目錄中未找到時(shí),不一定會(huì)使用默認(rèn)資源。系統(tǒng)在縮放時(shí)可能 改用其他密度特定資源提供更好的 效果。例如,查找低密度資源但該資源不可用時(shí), 系統(tǒng)會(huì)縮小資源的高密度版本,因?yàn)?系統(tǒng)可輕松以 0.5 為系數(shù)將高密度資源縮小至低密度資源,與以 0.75 為系數(shù) 縮小中密度資源相比,偽影更少。
使用配置限定符
設(shè)計(jì)替代布局和可繪制對(duì)象
三、最佳做法
支持多種屏幕的目標(biāo)是創(chuàng)建一款在 Android 系統(tǒng)支持的通用屏幕尺寸上都可以 正常運(yùn)行且顯示良好的應(yīng)用。本文檔 前面各節(jié)內(nèi)容介紹了 Android 系統(tǒng)如何使您的 應(yīng)用適應(yīng)屏幕配置,以及如何在不同的 屏幕配置上自定義應(yīng)用的外觀。本節(jié)提供另外一些提示以及有助于 確保應(yīng)用針對(duì)不同屏幕配置正確縮放的 技巧概覽。
1. 在 XML 布局文件中指定尺寸時(shí)使用 wrap_content、match_parent 或 dp 單位 。
????為 XML 布局文件中的視圖定義 android:layout_width 和 android:layout_height 時(shí),使用 "wrap_content"、 "match_parent" 或 dp 單位可確保在當(dāng)前設(shè)備屏幕上為 視圖提供適當(dāng)?shù)某叽纭?/p>
????例如,layout_width="100dp" 的視圖在 中密度屏幕上測(cè)出寬度為 100 像素,在高密度屏幕上系統(tǒng)會(huì)將其擴(kuò)展至 150 像素寬, 因此視圖在屏幕上占用的物理空間大約相同。
????類似地,您應(yīng)選擇 sp(縮放獨(dú)立的像素)來定義文本 大小。sp 縮放系數(shù)取決于用戶設(shè)置,系統(tǒng) 會(huì)像處理 dp 一樣縮放大小。
2. 不要在應(yīng)用代碼中使用硬編碼的像素值
????由于性能的原因和簡(jiǎn)化代碼的需要,Android 系統(tǒng)使用像素作為 表示尺寸或坐標(biāo)值的標(biāo)準(zhǔn)單位。這意味著, 視圖的尺寸在代碼中始終以像素表示,但始終基于當(dāng)前的屏幕密度。 例如,如果 myView.getWidth() 返回 10,則表示視圖在 當(dāng)前屏幕上為 10 像素寬,但在更高密度的屏幕上,返回的值可能是 15。如果 在應(yīng)用代碼中使用像素值來處理預(yù)先未針對(duì) 當(dāng)前屏幕密度縮放的位圖,您可能需要縮放代碼中使用的像素值,以與 未縮放的位圖來源匹配。
3. 不要使用 AbsoluteLayout(已棄用)
[AbsoluteLayout] 在 Android 1.5(API 級(jí)別 3)上便已棄用。
您應(yīng)改用 [RelativeLayout],它會(huì)使用相對(duì)定位 來放置其子視圖
4. 為不同屏幕密度提供替代位圖可繪制對(duì)象
????雖然系統(tǒng)會(huì)根據(jù)當(dāng)前屏幕 配置擴(kuò)展布局,但您在不同的屏幕尺寸上可能要調(diào)整 UI,以及提供 針對(duì)不同密度優(yōu)化的可繪制對(duì)象。
????如果需要精確控制應(yīng)用在不同 屏幕配置上的外觀,請(qǐng)?jiān)谂渲锰囟ǖ?資源目錄中調(diào)整您的布局和位圖可繪制對(duì)象。例如,考慮要顯示在 中密度和高密度屏幕上的圖標(biāo)。只需創(chuàng)建兩種不同大小的圖標(biāo) (例如中密度使用 100x100,高密度使用 150x150),然后使用適當(dāng)?shù)南薅ǚ?以適當(dāng)?shù)姆较蚍胖脙蓚€(gè) 變體:
res/drawable-mdpi/icon.png //for medium-density screens
res/drawable-hdpi/icon.png //for high-density screens