Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的屏幕多樣性支持

Android的屏幕多樣性支持

編輯:關於Android編程

 

前言


運行Android系統設備的屏幕尺寸和密度千變萬化。然而對於應用程序來說,Android系統為所有設備提供了一個統一的開發環境,並且由系統處理了大部分應用程序界面與實際屏幕的適配工作。同時,系統也提供了相應的API允許你在特定的屏幕尺寸或屏幕密度上為你的應用程序UI做特定的調整,以便在不同配置的屏幕上優化你的UI。例如,你可能需要在平板和手機上顯示不一樣的UI效果。

盡管系統能夠自動將你的應用程序UI通過縮放或重置大小來適配不同的屏幕,但你仍然需要為你的應用程序適配不同尺寸和密度的屏幕做一點優化工作。這樣,你才能夠最大程度優化不同設備上的用戶體驗,讓你的用戶相信你的應用就是為他們的設備設計的,而不是通過簡單的UI拉伸來填充他們的設備屏幕。

通過本文介紹的方法,你能夠創建一個顯示正確的應用程序,並且簽名打包出一個在其所有支持的設備屏幕上都能獲得優越用戶體驗的apk文件。

注意: 本文所有內容都假定你的應用程序只支持Android 1.6(API Level 4)或者更高的Android版本。如果你的應用程序需要支持Android 1.5或者更低的版本,請先閱讀Strategies for Android 1.5.

另外,要知道從Android 3.2開始引入了很多新的API,這些API能夠讓你為不同屏幕尺寸更好的調整應用程序所使用的layout資源。如果你開發的應用需要針對平板進行優化,這些新特性就更加重要。更多的細節可以參考下面Declaring Table Layouts for Android 3.2章節。

 

屏幕支持概覽(Overview of Screens Support)


本章節為Android支持多樣屏幕的概述。包括對本文檔或API中涉及的術語及概念進行介紹說明,對Android系統所支持的屏幕配置屬性的總結,以及API和底層屏幕兼容特性的概述。

2.1 術語及概念(Terms and concepts)

2.1.1 Screen size(屏幕尺寸)

實際的物理尺寸,根據屏幕的對角線來測量。

為了簡單起見,Android將全部屏幕尺寸歸類成4種通用尺寸:smallnormallargeextra-large

2.1.2 Screen density(屏幕密度)

指的是屏幕上一個物理單位區域中的像素數量,通常使用dpi(每英寸多少點)為單位。例如,相對於“normal”或者“high”密度的屏幕,在相同物理區域上“low”密度的屏幕擁有的像素要更少。

為了簡單起見,Android將全部屏幕密度歸類成6中通用密度:lowmediumhighextra-hightextra-extra-highextra-extra-extra-high

2.1.3 Orientation(屏幕方向)

屏幕的方向是從用戶的視覺角度來說的。屏幕方向不是landscape(橫向)就是portrait(豎向),分別意味著屏幕的寬高比更寬或者更高。注意不單要做不同屏幕的適配,還要做同一個屏幕不同方向情況下的適配,因為如果用戶在應用程序運行的過程中旋轉設備可能會引起屏幕方向的改變。

2.1.4 Resolution(分辨率)

表示一塊屏幕上總的物理像素數量。當支持多樣屏幕適配的時候,應用程序不直接使用分辨率,應用程序應當使用上文所說的系統通用尺寸和通用密度類別,只需關心屏幕尺寸和密度就可以了。

2.1.5 Density-independent pixel(dp,密度無關的像素)

一種虛擬的像素單位。當你在UI的layout資源中定義layout的尺寸或位置的時候,你應當使用這種虛擬像素單位。

1個單位的虛擬像素等於160dpi屏幕上的一個物理像素點,這也是系統將“medium”屏幕密度作為基准密度的原因。在運行的時候,如果有需要,系統會基於實際屏幕的密度對dp單位進行縮放。dp單位和實際屏幕px像素單位的轉換很簡單:px = dp * (dpi/160)。例如,在240dpi的屏幕上,1dp等於1.5px。當你定義應用程序UI的時候,你應當使用dp來保證你的UI能夠正確顯示在不同的屏幕上。

2.2 屏幕支持的范圍(Range of screens supported)

從Android 1.6(API Level 4)開始,Android提供了多種屏幕尺寸和密度的支持,以對應不同的設備屏幕配置。你可以使用系統提供的這些功能針對每一種屏幕配置優化你的應用程序界面,確保你的應用程序能夠在每一種屏幕上提供最好的用戶體驗,而不單單只是基本正常顯示。

為了簡化你為不同屏幕適配用戶界面的工作,Android將實際的屏幕尺寸和密度歸類為如下:

4種通用的尺寸:smallnormallargexlarge

注意: 從Android 3.2(API Level 13)開始,這些尺寸分類已經被棄用,以便於基於可用屏幕寬度來管理屏幕尺寸這種新技術的實現。如果你是為Android 3.2或更高版本的系統開發,請參考下面 Declaring Tablet Layouts for Android 3.2 章節獲取更多信息。

6種通用密度:
ldpi(low) ~ 120dpi mdpi(medium) ~ 160dpi hdpi(high) ~ 240dpi xhdpi(extra-hight) ~ 320dpi xxhdpi(extra-extra-high) ~ 480dpi xxxhdpi(extra-extra-extra-high) ~ 640dpi

這些通用尺寸和通用密度全部都是以normal尺寸和mdpi密度作為基准來調整的。之所以使用這個基准是因為這是第一部Android設備T-Mobile G1的屏幕配置,也就是HVGA屏幕(直到Android 1.6之前,這都是Android唯一支持的屏幕配置)。

每一套通用尺寸和通用密度都會覆蓋一定范圍的真實屏幕尺寸和密度。例如,兩台設備都要求使用normal尺寸,但實際上手動測量兩台設備屏幕的真實尺寸和縱橫比會稍稍不同。同樣的,兩個設備都要求使用hdpi密度,但實際上兩台設備的像素密度稍稍不同。Android系統會將這些差異抽象化,因此你可以直接提供通用尺寸或者通用密度的UI,讓系統在有需要的時候自動進行校准。下圖粗略的展示了不同的尺寸和密度與通用尺寸和通用密度的對應關系:

通用尺寸和通用密度對應的大致范圍

圖1<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPiDV5sq1s9+059Prw9y2yLrNzajTw7PftOfNqNPDw9y2yLbU06a1xLTz1sK3ts6no6jXotLizbzW0Mr919bKx7K7zKvXvMi3tcSjqTwvcD4NCjxwPrWxxOPOqrK7zay1xMbBxLuz37Tnyei8xlVJtcTKsbryo6zE47vht6LP1sO/0rvW1ra809DX7tChtcS/1bzk1rXP3tbGoaPS8rTLo6zPtc2zttTJz8PmzOG1vbXEw7/Su9bWzajTw8bBxLuz37Tntry2qNLlwcvP4LnYwaq1xNfu0KG94s72tsiho9fu0KG1xLPftOfOqjFkcKOsZHDKx8TjtqjS5WxheW91dLXEyrG68tOmuMPKudPDtcS1pc67o6zKudPD1eK49rWlzruyxcTcyMPPtc2ztKbA7VVJ0vLGwcS7w9y2yLK7zazS/cbwtcSx5LuvoaM8L3A+DQp4bGFyZ2XGwcS71+7Qob3izva2yM6qOTYwZHAqNzIwZHAgbGFyZ2XGwcS71+7Qob3izva2yM6qNjQwZHAqNDgwZHAgbm9ybWFsxsHEu9fu0KG94s72tsjOqjQ3MGRwKjMyMGRwIHNtYWxsxsHEu9fu0KG94s72tsjOqjQyNmRwKjMyMGRwDQo8YmxvY2txdW90ZT4NCgk8cD48c3Ryb25nPtei0uKjujwvc3Ryb25nPiDV4tCp1+7QocbBxLu94s72tsjU2kFuZHJvaWQgMy4w1q7HsLXEsOaxvsnPsqLDu9PQw/fIt7ao0uWjrNLytMujrMTjv8nE3Lvht6LP1tK70KnJ6LG4tcTGwcS7s9+059Tabm9ybWFsus1sYXJnZdauvOSxu7TtzvO56cDgwcuho8HtzeKjrNXi0Km94s72tsjSsrv509rGwcS7tcTO78DtveLO9rbIo6zL+dLUw7/MqMnosbi2vLj3srvP4M2sJm1kYXNoOyZtZGFzaDvA/cjn0ruyvzEwMjQqNzIwtcTGvbDlyrnTw8HLz7XNs8C4uvPB9Lj406bTw7PM0PK1xL/J08O/1bzku+G4/MnZo6zS8s6qsr+31r/VvOSxu8+1zbPAuNW808PBy6GjPC9wPg0KPC9ibG9ja3F1b3RlPg0KPHA+zqqyu82stcTGwcS7s9+057rNxsHEu8PctsjTxbuvxOO1xNOm08OzzNDyVUmjrMTjv8nS1M6q0rvQqc2o08Oz37Tnus3NqNPDw9y2yMzhuanM5ru7tcTXytS0oaPNqLOjx+m/9s/Co6zE49OmuMPOqrK7zayz37TntcTGwcS7zOG5qb/JzOa7u7XEbGF5b3V018rUtKOs0tS8sM6qsrvNrMPctsi1xMbBxLvM4bmpv8nM5ru7tcTNvMas18rUtKGj1NrUy9DQtcTKsbryo6zPtc2zu+G9q7Wxx7DJ6LG4tcTGwcS70+vNqNPDs9+057vyzajTw8Pctsi9+NDQttSxyKOs19S2r86qxOO1xNOm08OzzNDy0aHU8brPysq1xNfK1LShozwvcD4NCjxwPsTjsrvQ6NKqzqrDv9K71tbNqNPDxsHEu7PftOe6zc2o08PGwcS7w9y2yLXE1+m6z7a8zOG5qdK7zNe/yczmu7u1xNfK1LSho8+1zbPM4bmpwcvHv7TztcS85sjduabE3KOsxNy5u72rxOO1xNOm08OzzNDy5NbIvrW9srvNrMnosbjGwcS7yc+yorSmwO2087K/t9a1xM7KzOKho7Wrx7DM4crHxOPU2sq1z9bE47XEVUnKsdLRvq3KudPDwcvP4LnYtcS8vMr1o6zV4tH5ssXE3Mq5z7XNs9PF0cW1xLX31ftVSbTz0KGjqM/qz7jH67Lpv7TPwsPmPHN0cm9uZz62wMGiw9y2yDwvc3Ryb25nPtXCvdqjqaGjPC9wPg0KPGJsb2NrcXVvdGU+DQoJPHA+PHN0cm9uZz7XotLio7o8L3N0cm9uZz4g0rvMqMnosbi1xM2o08PGwcS7s9+057rNzajTw8bBxLvD3LbItcTM2NDU1q685MrHz+C7pbbAwaK1xKGjwP3I56Os0ru/6VdWR0G1xGhpZ2jD3LbIxsHEu72ru+HKudPDbm9ybWFsxsHEu7PftOejrNLyzqrL/LXEzu/A7bPftOfT61QtTW9iaWxlIEcx0rvR+aOotdrSu7K/QW5kcm9pZMnosbijrNKyysfGwcS7xeTWw7fWwOC1xLv517yjqaGjwe3Su7e9w+ajrNK7v+lXVkdBtcRtZWRpdW3D3LbIxsHEu72ru+HKudPDbGFyZ2XGwcS7s9+056GjvqG53Mv8w8e1xL3izva2yMrHz+DNrLXEo6jX3M/xy9jP4M2so6mjrLWrysfV4r/pV1ZHQSBtZWRpdW3D3LbItcTGwcS7w9y2yLHIvc+1zaOs1eLS4s6218XL/LXEz/HL2LXjzu/A7bPftOe4/LTzo6zS8rTLssW74cq51fu/6cbBxLuxyLv517zGwcS7o6hub3JtYWyz37TntcTGwcS7o6m4/LTzoaM8L3A+DQo8L2Jsb2NrcXVvdGU+DQo8aDIgaWQ9"23-獨立的密度density-independence">2.3 獨立的密度(Density independence)

當你的應用程序實現“密度獨立”時,即使是在不同密度的屏幕上,你的UI元素也將保留同樣的物理尺寸(從用戶的角度來看)。

保持密度獨立是一件重要的事情,因為如果沒有保持密度獨立,一個UI元素(例如一個按鈕)將會在低密度屏幕上顯示的很大,而在高密度屏幕上顯示的很小。像這樣密度相關的尺寸如果一改變,就會導致你的應用程序產生布局或者可用性的問題。圖2和圖3分別顯示了一個應用程序如果沒有保持密度獨立和保持密度獨立的顯示效果。

沒有保持密度獨立效果

圖2 沒有支持不同屏幕密度的應用程序示例,分別是low、medium和high密度的屏幕效果。

保持密度獨立效果

圖3 很好支持不同屏幕密度的應用程序示例(也就是密度獨立),分別是low、medium和high密度的屏幕效果。

Android系統通過兩種方式來幫助你的應用程序實現密度獨立:

系統根據當前屏幕的實際密度自動縮放dp單位到合適的大小 在需要的情況下,系統根據當前屏幕的實際密度自動縮放圖片資源到合適的尺寸

在圖2中,TextView和ImageView的尺寸通過像素(px單位)來指定,因此這些View的物理尺寸在low密度屏幕上顯示會變得很大,在high密度屏幕上顯示的很小。這是因為盡管它們的屏幕實際物理尺寸大小一樣,但是high密度的屏幕上每英寸擁有的像素點更多(反過來也就是同樣數量的像素點在high密度屏幕上能夠填充的范圍更少)。由於密度無關像素的基准是medium密度的屏幕,所以在上面兩張圖片中medium密度的屏幕顯示效果是一樣的。對於low密度和high密度的屏幕,系統會自動分別為dp值的實際尺寸縮小或放大到合適尺寸。

大多數情況下,確保你的應用程序與密度無關,你只需要簡單的將所有layout中的尺寸值使用dp單位或者“wrap_content”屬性值聲明。這樣系統也才能夠根據當前屏幕的密度選擇合適的縮放因子將圖片資源縮放到合適的尺寸。

然而,從上面的截圖中,你可能已經發現圖片的縮放會導致圖片模糊或者產生齒距。為了避免這種情況,你需要為不同的密度提供可替換的圖片資源。例如,你應該為high密度的屏幕提供高分辨率的圖片,系統會在high密度屏幕上使用高分辨率的圖片來縮放,而不是直接使用medium密度的圖片。下面的章節會詳細說明如何為不同配置的屏幕提供可替換掉的資源。

 

如何支持多樣屏幕(How to Support Multiple Screens)


Android支持多樣屏幕的基礎是它能夠根據當前屏幕配置適當渲染應用程序布局和圖片的能力。系統正確處理了每一塊屏幕上的UI渲染工作,這些操作是通過縮放layout來適配屏幕尺寸/密度,或者縮放圖片來適配屏幕密度。為了更好的處理不同屏幕配置之間的差異,你還應該做以下工作:

在manifest中明確聲明你的應用程序所支持的屏幕尺寸
通過聲明你的應用程序所支持的屏幕尺寸,你可以確保只有符合屏幕配置條件的設備才能下載你的應用程序。聲明所支持的不同屏幕尺寸也會影響系統如何在更大的屏幕上繪制你的應用程序——無論你的應用程序是否運行在屏幕兼容模式下。
聲明你的應用程序所支持的屏幕尺寸,你需要在manifest文件中聲明標簽。

為不同的屏幕尺寸提供不同的layout
默認情況下,Android會調整應用程序的layout大小來適配當前設備屏幕。在大多數情況下,這麼做沒什麼問題。然而,在有些情況下,你的UI可能看起來沒那麼好,需要針對不同屏幕尺寸做一定的調整。例如,在大屏幕上面,你可能想要調整一些元素的位置和尺寸來利用大屏幕多出來的屏幕空間,或者在小屏幕上你可能需要調整下尺寸才能讓全部元素都能正確顯示在屏幕上。
提供特定尺寸資源,你可以使用的配置修飾符有smallnoramllargexlarge。例如,為extra-large屏幕提供的layout資源應該放在layout-xlarge/資源文件夾下。
從Android 3.2(API level 13)開始,上面所說的尺寸類別已經被棄用,你應該使用swdp配置修飾符作為替代品來定義你的layout資源要求的最小可用寬度。例如,如果你的多窗口平板布局要求最少600dp的屏幕寬度,你就應該使用layout-sw600dp/資源文件夾。更多關於這種聲明layout資源的新技術,請參考下面Declaring Table Layouts for Android 3.2章節。

為不同的屏幕密度提供不同的圖片資源
默認情況下,Android會自動縮放你的bitmap圖片(.png.jpg,和.gif文件)和Nine-Patch圖片(.9.png文件),這樣它們才能在每一台設備上渲染出合適的物理尺寸。例如,如果你的應用程序只為基准密度,也就是medium屏幕密度(mdpi)提供了圖片資源,那麼系統將會在high密度屏幕上放大這些圖片,在low密度屏幕上縮小這些圖片。這些縮放可會到引起圖片顯示問題。為了確保你的圖片看起來顯示效果最好,你應該為不同密度的屏幕提供不同分辨率的圖片進行替換。
提供特定密度的資源,你可以使用的配置修飾符(下面章節詳細介紹)有ldpi(low)、mdpi(medium)、hdpi(high)、xhdpi(extra-high)、xxhdpi(extra-extra-high)、xxxhdpi(extra-extra-extra-high)。例如,想要為high屏幕密度提供的圖片應該放在drawable-hdpi/資源文件夾下。

注意: mipmap-xxxhdpi修飾符只有在需要為xxdpi屏幕密度的設備提供比通常更大的啟動圖標時才必須使用的。你不需要為所有圖片都提供xxxdpi規格的版本。

有些設備會將啟動圖標放大多達25%。例如,如果你的最高啟動圖標密度已經是extra-extra-hight密度,縮放程序將會使啟動圖標的顯示效果變得模糊。因此,你應該在mipmap-xxxhdpi資源文件夾中提供更高密度的啟動圖標,系統會直接使用這個圖標,而不是去放大低密度版本的圖片。

參考提供xxx-high密度啟動圖標章節獲取更多詳細信息。除了啟動圖標,你不應該為其它UI元素提供xxxhdpi類型的圖片。

注意: 將你的啟動圖標放在res/mipmap-[density]資源文件夾下,而不是res/drawable-[density]資源文件夾。因為,不管你的應用程序實際安裝的設備屏幕分辨率是多少,Android系統都會保留這類密度修飾符的資源文件夾,例如mipmap-xxxhdpi。這樣啟動器才能夠選擇你的應用程序最佳分辨率的圖標顯示在home上面。更多關於mipmap文件夾的信息,請參考Managing Projects Overview

所有的這些尺寸和密度的配置修飾符一一對應上面屏幕支持的范圍(Range of screens supported) 章節所提到的通用尺寸和通用密度。

注意: 如果你不熟悉這些配置修飾符,以及系統如何使用它們來適配替換資源,請參考Providing Alternative Resources。

在運行的過程中,系統通過以下幾個步驟來確保UI在當前屏幕上能有最好的顯示效果:

系統使用適當的可替換資源
根據當前屏幕的尺寸和密度,系統將使用應用程序提供的對應尺寸和密度修飾符資源文件夾中的資源。例如,一台high密度的設備要使用應用程序的一張圖片資源,系統將會在應用程序的全部資源文件夾中挑選最匹配當前設備配置的資源文件夾。取決於可用的替代資源,使用hdpi修飾符的資源文件夾(例如drawable-hdpi)可能是最佳的匹配,系統就會使用這個文件夾中的圖片資源。

如果沒有找到匹配的可用資源,系統將會使用默認的資源加以放大或縮小來適配當前屏幕尺寸和密度
所謂的默認資源文件夾就是那些不帶任何配置修飾符的資源文件夾。例如,drawable/資源文件夾中的資源就是默認的圖片資源。系統會假設默認的資源是根據屏幕尺寸和密度的基准來設計的,也就是normal尺寸和medium密度。因此,系統將會為高密度的屏幕放大默認圖片,為低密度屏幕縮小默認圖片。
然而,當系統查找對應當前屏幕的密度修飾符資源但又找不到匹配的資源時,系統不一定就會使用默認的資源。系統也有可能會使用其它密度修飾符的資源來作替代,以便放大縮小後能夠取得最好的效果。例如,當系統尋找low密度的資源但是又找不到的時候,系統會優先用high密度的資源進行縮小,因為相對於使用0.75縮放因子將medium密度資源縮小成low密度資源,系統使用0.5的縮放因子將high密度資源縮小成low密度的資源會更加容易和節省開銷。

更多關於Android系統如何選取帶配置修飾符的可替代資源來適應設備配置信息,請參考How Android Finds the Best-matching Resource。

3.1 使用配置修飾符(Using configuration qualifiers)

Android支持一系列配置修飾符,通過這些修飾符,你可以控制系統如何基於當前設備屏幕的特性選擇對應的替代資源。所謂的配置修飾符就是一串字符串,用於附加到你的Android項目資源文件夾後面,以指明該資源文件夾所針對的配置。

配置修飾符的使用方式:

在你的項目res/文件夾下創建一個新的文件夾,並以-格式命名

指的是標准的資源名稱(例如drawable或者layout)。 指的是下面表1中的配置修飾符,用於指明文件夾中的資源對應的屏幕配置(例如hdpixlarge

將適當的配置資源放到對應的資源文件夾中。這些資源的名稱必須與默認的資源文件一模一樣。

例如,xlarge是針對extra-large屏幕的配置修飾符。當你將這個修飾符添加到資源文件夾後面時(例如layout-xlarge),它向系統指明這些資源應該用於extra-large屏幕的設備。

表1 允許你為不同屏幕配置指定資源的配置修飾符

屏幕特性 修飾符 描述 尺寸 small 針對small通用屏幕尺寸的資源 normal 針對normal通用屏幕尺寸的資源(也是所用尺寸的基准尺寸) large 針對large通用屏幕尺寸的資源 xlarge 針對extra-large通用屏幕尺寸的資源 密度 ldpi 針對low通用屏幕密度(ldpi)的資源(大約120dpi) mdpi 針對medium通用屏幕密度(mdpi)的資源(大約160dpi,也是通用屏幕密度的基准) hdpi 針對high通用屏幕密度(hdpi)的資源(大約240dpi) xhdpi 針對extra-high通用屏幕密度(xhdpi)的資源(大約320dpi) xxhdpi 針對extra-extra-high通用屏幕密度(xxhdpi)的資源(大約480dpi) xxxhdpi 針對extra-extra-extra-high通用屏幕密度的資源(大約640dpi)。只用於存放啟動圖標,詳情請參考上面章節。 nodpi 針對所有屏幕密度的資源。這些資源與密度無關,無論當前屏幕密度是多少,系統都不會放大縮小這些資源。 tvdpi 針對介於mdpi和hdpi之間屏幕密度的資源,大約是213dpi。這不是一個主要密度類型,它主要是為電視機屏幕而設置。大多數app都不需要這種類型,提供的mdpi和hdpi資源已經能夠滿足大部分app的需求,並且在需要的時候系統也會自動對這些資源進行縮放到合適的大小。如果你需要提供tvdpi類型的資源,你需要使用1.33倍mdpi的縮放因子來設置tvdpi資源的大小。例如,一張針對mdpi屏幕的100x100px圖片,對應tvdpi屏幕的尺寸是133x133px。 方向 land 針對橫向屏幕的資源(寬寬高比) port 針對豎向屏幕的資源(高寬高比) 長寬比 long 針對屏幕的豎屏或寬屏長寬比(分別對應豎向或者橫向方向)比基准屏幕配置更大的屏幕資源 notlong 針對屏幕的豎屏或者寬屏長寬比比基准屏幕配置更小的屏幕資源

 

注意: 如果你的應用程序是為Android 3.2或者更高的系統版本開發的,那麼你需要查看下面Declaring Table Layouts for Android 3.2章節,在定義layout資源的時候使用新的配置修飾符來聲明所適配的屏幕尺寸(替換表一中的尺寸修飾符)

更多關於這些修飾符如何匹配當前屏幕實際尺寸和密度的內容,請參考前面屏幕支持范圍(Range of Screens Support) 章節。

例如,下面的應用程序的資源目錄為不同的屏幕尺寸提供了不同的layout資源,為不同的屏幕密度提供了不同的圖片,並使用mipmap/資源文件夾提供啟動圖標:

res/layout/my_layout.xml              // layout for normal screen size (default)  
res/layout-large/my_layout.xml        // layout for large screen size
res/layout-xlarge/my_layout.xml       // layout for extra-large screen size
res/layout-xlarge-land/my_layout.xml  // layout for extra-large in landscape orientation

res/drawable-mdpi/graphic.png         // bitmap for medium-density
res/drawable-hdpi/graphic.png         // bitmap for high-density
res/drawable-xhdpi/graphic.png        // bitmap for extra-high-density
res/drawable-xxhdpi/graphic.png       // bitmap for extra-extra-high-density

res/mipmap-mdpi/my_icon.png         // launcher icon for medium-density
res/mipmap-hdpi/my_icon.png         // launcher icon for high-density
res/mipmap-xhdpi/my_icon.png        // launcher icon for extra-high-density
res/mipmap-xxhdpi/my_icon.png       // launcher icon for extra-extra-high-density
res/mipmap-xxxhdpi/my_icon.png      // launcher icon for extra-extra-extra-high-density

更多關於如何使用可替代資源,以及完整的配置修飾符列表(不單只是屏幕配置修飾符),請參考Providing Alternative Resource.

要注意,系統在運行的時候會選擇哪一種資源作為“最合適”的資源是根據一定的邏輯規則來決定的。也就是,無論在哪種屏幕下,你所使用的修飾符都不一定要跟當前屏幕配置完全匹配,以便系統能夠自己選擇。具體來講,當基於尺寸修飾符選擇資源的時候,如果沒有更匹配的資源,系統會選擇為比當前屏幕更小的屏幕所提供的資源(例如,在需要的時候large尺寸的屏幕可能會使用normal尺寸的資源)。另外,如果唯一能夠使用的資源是為比當前設備屏幕更大的屏幕所提供的,那麼系統將不會使用這些資源,並且應用程序會崩潰(例如,所有的layout資源都添加了xlarge修飾符,但是當前設備屏幕是normal尺寸屏幕)。更多關於系統選擇資源的信息,請參考How Android Finds the Best-matching Resource.

小貼士: 如果你有一些圖片資源希望系統永遠不進行縮放(可能你想要在程序運行時由自己來控制和調整),那麼你應該把這些資源放到nodpi配置修飾符的資源文件夾中。在這個配置修飾符文件夾中的資源是密度無關的資源,系統永遠不會對它們進行縮放。

3.2 設計可替代的布局和圖片資源(Designing alternative layouts and drawables)

需要提供哪些可替代資源是根據你的應用程序需求來決定的。通常情況下,你需要使用尺寸和方向類的修飾符來提供可替代的layout資源,以及使用密度類的修飾符提供可替代的圖片資源。

下面章節將分別總結為什麼你要使用尺寸類或密度類修飾符提供可替代的layout資源或者圖片資源。

3.2.1 可替代布局資源(Alternative layouts)

通常情況下,只要你在不同配置的屏幕上測試你的應用程序,你就能知道是否需要為不同的屏幕尺寸提供可替換的layout資源了。例如:

當你在small屏幕上測試的時候,你可能會發現你的layout不能很好的填充在屏幕上。例如,在small屏幕上,屏幕的寬度內不能填滿多個按鈕。這種情況下,你需要為small屏幕提供可替代的layout資源來調整按鈕的尺寸和位置。

當你在extra-large屏幕上測試的時候,你可能會發現你的layout不能高效利用大屏幕的優勢,並且整個布局都被拉伸來填滿屏幕。這種情況下,你需要為extra-large屏幕提供可替代的layout資源,重新提供為大屏幕(例如平板)優化的UI。
盡管你的應用程序不為大屏幕提供可替代layout資源也能夠正常運行,但對用戶來說,提供可替代資源能讓用戶感覺這個應用程序就是為了他的設備所設計的。如果UI都被拉伸了,用戶對應用程序的用戶體驗可能很反感。

另外,當測試橫向屏幕與豎向屏幕時,你可能會發現豎向屏幕底部的UI元素在橫向屏幕上顯示在屏幕右邊。

總結,你應該確認你的應用程序布局是存在以下幾點:

需要適配小屏幕(這樣用戶才能正常使用你的應用程序) 是否有對大屏幕進行優化以充分利用大屏幕帶來的額外空間 是否有對橫向和豎向屏幕進行優化

如果你的UI所使用的圖片即使在被系統縮放layout之後也要填充整個view(例如按鈕的背景圖片),那麼你應該使用Nine-Patch圖片文件。Nine-Patch(點九圖)文件實際上就是在png圖片文件的基礎上指定了兩個維度上的可拉伸區域。當系統拉伸使用點九圖的的view時,所使用的點九圖也會被拉伸,只不過拉伸的只是點九圖上指定的可拉伸區域。因此,如果使用點九圖的話就不需要為不同的屏幕尺寸提供不同的圖片,因為點九圖能夠自動調整到任何尺寸。然而,你還是要為不同的屏幕密度提供可替代的點九圖資源。

3.2.2 可替代圖片資源(Alternative drawables)

幾乎每一個應用程序都需要為不同的屏幕密度提供可替代的圖片資源,因為每一個應用程序都有一個啟動圖標,至少要保證這個啟動圖標在每一塊屏幕上都有良好的顯示效果。同樣,如果你的應用程序中還有其它的圖片(例如菜單圖標或者其它圖形),你都應該為不同的屏幕密度給每一張圖片都提供可替換的版本。

注意: 你只需要為圖片文件(.png.jpg.git)和Nine-Patch文件提供密度相關的資源。如果你使用XML文件來定義圖形、顏色或者其它drawable resources,那麼你只需要在默認的圖片文件夾(drawable/)中保留一份代碼就可以了。

要為不同的屏幕密度創建可替代的圖片資源,你應該遵循六種通用屏幕密度圖片的縮放比例3:4:6:8:12:16。例如,如果你有一張為medium屏幕密度設計的圖片尺寸是48x48像素,那麼其它尺寸應該為:

36x36(0.75x),low屏幕密度 48x48(1.0x 基准),medium屏幕密度 72x72(1.5x),high屏幕密度 96x96(2.0x),extra-high屏幕密度 180x180(3.0x),extra-extra-high屏幕密度 192x192(4.0x),extra-extra-extra-high屏幕密度(只需要啟動圖標,參考上面章節)

圖4 每一種屏幕密度之間圖片的尺寸關系
屏幕密度之間圖片尺寸關系

更多關於設計圖標的信息,請參考Icon Design Guidelines。裡面包含了各種圖片資源的尺寸信息,包括啟動圖標、菜單圖標,狀態欄圖標、標簽圖標等等。

 

為Android 3.2聲明平板布局(Declaring Tablet Layouts for Android 3.2)


自從第一代運行Android 3.0系統的平板開始,為平板定義layout的重要方法就是把平板layout放到帶xlarge配置修飾符的資源文件夾中(例如res/layout-xlarge)。為了兼容其它類型的平板以及屏幕尺寸(特別是7英寸的平板),Android 3.2開始引入新的方法來為更碎片化的屏幕尺寸指定資源。相對於嘗試將你的layout適配到通用的尺寸(例如large或者xlarge),新的技術是基於你的layout需要的空間大小(例如寬度要600dp)來調整。

這麼設計的原因是當使用通用尺寸為7英寸平板做適配時,事情會變得非常棘手,因為7英寸平板在通用尺寸歸類技術上與5英寸手機都劃分為同一組(large類型)。盡管這種設備從尺寸上來看非常相近,但是對應用程序的UI占用的空間大小來說是顯著不同的,同樣用戶交互習慣也不同。因此,7英寸和5英寸屏幕不應該使用相同的layout資源。為了實現為這兩種不同的屏幕尺寸提供不同的layout資源,Android現在允許你根據應用程序layout實際需要的尺寸來聲明layout資源的類型,並且要使用dp單位。

例如,你在為平板設備特別設計好layout資源之後,應該在小於600dp寬度的屏幕上檢查這些layout是否能使用。因為使用這些平板layout資源的條件就是屏幕的最小尺寸是否滿足你聲明的尺寸。因此,現在你可以為你的應用程序UI指定一些只有在可用寬度最少為600dp時才能使用的layout資源。

你應該在指定一個寬度的同時,以這個寬度作為最小尺寸來進行設計。否則,你需要在完成layout資源後測試你的layout能夠支持的最小寬度。

注意: 所有使用新API指定的數值都是密度無關的值(dp),所以你的layout尺寸也應該使用dp單位來定義,因為你應該關心的只是系統計算屏幕密度後得出來的可用屏幕空間總值(強烈反對使用物理像素單位)。更多關於密度無關像素的內容,請參考上面術語與概念(Terms and concepts) 章節。

4.1 使用新的尺寸修飾符(Using new size qualifiers)

表2總結了能夠根據屏幕可用空間大小來指定資源的配置修飾符。相比較於傳統的通用屏幕尺寸類型(small、normal、large、xlarge),新的修飾符能基於你的應用程序支持的屏幕尺寸給你提供更多的控制。

注意: 你使用這些修飾符指定的尺寸不是實際上的屏幕尺寸。實際上,這些尺寸是你的Activity窗口可用寬度或者高度的dp值。Android系統可能會占用一些屏幕空間來顯示系統UI(例如屏幕底部的系統欄或者頂部的狀態欄),因此一些屏幕可能無法使用你的layout資源。也就是說,你聲明的尺寸應該是你的Activity需要的尺寸——系統會統計系統UI占用的空間後決定給你的layout提供多大的空間。另外也要注意Action Bar也是你的應用程序組成部分,盡管你的layout資源沒有聲明它,但是它同樣要占用你的layout可用空間的一部分,你在設計的時候也要把這部分給計算進去。

表2 新的屏幕尺寸配置修飾符(Android 3.2引入)

屏幕配置 修飾符 說明 最小寬度 (smallestWidth) swdp
例如:sw600dp、sw720dp 屏幕的基本尺寸,由屏幕可用區域的最短尺寸所決定。准確的說,設備的最小寬度就是屏幕最短的可用高度和寬度(你也可以認為是屏幕有可能呈現的最短寬度)。你可以使用這個修飾符來確保無論當前屏幕的方向如何,你的應用程序UI最少可用的寬度都有 dp。
例如,你的應用程序無論任何時候都要求屏幕寬度最少要600dp,那麼你就可以使用這個修飾符創建一個layout資源並放到res/layout-sw600dp/的資源文件夾中。系統只會在當前屏幕可用最小尺寸為600dp時才會使用這個資源,並且不管這個600dp是用戶認為的高度還是寬度。最小寬度是一個固定的屏幕尺寸,是屏幕的一個屬性。無論當前屏幕的方向如何,設備的最小寬度都是不會變的。
設備的最小寬度要考慮到屏幕的裝飾空間和系統UI。例如,如果設備屏幕有一些持久性的UI沿著最小寬度的軸心占據一定的空間,那麼系統聲明的最小寬度值將會比實際屏幕的尺寸小,因為被占據的這部分屏幕空間你的UI永遠無法使用。
這是相對於傳統通用尺寸修飾符(small、normal、large、xlarge)的替代方案,它允許你根據你的UI實際需要的可用尺寸定義離散的數值。使用最小寬度來定義通用尺寸是非常有用的,因為寬度通常是設計一個layout的關鍵因素。一個UI通常可以上下滑動,但是卻在橫向空間上無法擴展。可用寬度同時也是決定是否在手機上顯示單窗口layout或者平板上顯示多窗口layout的關鍵因素。因此,你應該更加關注每一種設備上可能的最小寬度值是多少。 可用屏幕寬度 (Available screen width) wdp
例如:w720dp、w1024dp 通過值指定該資源文件夾中資源最小可用寬度的dp值。當屏幕在橫向和豎向之間切換的時候,系統相應的寬度值會改變,以實時更新你的UI當前可用的實際寬度。
這通常對判斷是否使用多窗口layout非常有用,因為盡管是在平板設備上,你通常也不希望豎向多窗口布局與橫向的相同。因此,你可以使用這個修飾符來聲明layout所需要的最小寬度,而不是同時使用屏幕尺寸和方向的修飾符來聯合聲明。 可用屏幕高度 (Available screen high) hdp
例如:h720dp、h1024dp 通過值指定該資源文件夾中資源最小可用高度的dp值。當屏幕在橫向和豎向之間切換的時候,系統相應的高度值會改變,以實時更新你的UI當前可用的實際高度。
與使用wdp來定義layout所需寬度一樣,使用hdp來定義你的layout所需要的高度也是非常有用的,它可以避免使用屏幕尺寸和方向兩種修飾符來進行組合定義。然而,大多數app不需要這個修飾符。因為UI在需要的時候一般都能夠上下滑動,在可用高度的控制上本身就比較靈活,不像可用寬度無法擴展。


盡管看起來使用這些修飾符要比使用通用屏幕尺寸類修飾符更復雜,但是一旦你確定了你的UI需求,使用這些修飾符實際上要簡單得多。當你在設計UI的時候,你所關心的最主要問題應該是你的應用程序在手機風格的UI和平板風格的UI(使用多窗口)之間切換時,你所能使用的實際尺寸。這個UI風格切換的關鍵點取決於你特定的設計——可能你的平板layout需要720dp的寬度,也有可能600dp或者480dp就夠了,還有可能是介於兩者之間的某個值。使用表二中的修飾符,你就能精確的控制你的layout切換臨界值。

更多關於這些尺寸配置修飾符的資料,請參考Providing Resource文檔。

4.2 配置實例(Configuration examples)

為了幫助你針對不同類型的設備進行設計,下面是一些典型屏幕寬度的數值:

320dp:一種典型的手機屏幕(240x320 ldpi、320x480 mdpi、480x800 hdpi等等) 480dp:像是平板設備的過渡線(480x800 mdpi) 600dp:一種7英寸平板(600x1024 mdpi) 720dp:一種10英寸平板(720x1028 mdpi、800x1280 mdpi等等)

使用表2中的尺寸修飾符,你的應用程序可以根據你想要的寬度(或高度)來設定准確的數值去促使手機和平板分別使用不同的layout資源。例如,如果600dp是你的平板layout能夠支持的最小可用寬度值,你就可以提供下面兩套layout資源:

res/layout/main_activity.xml           # 手機使用
res/layout-sw600dp/main_activity.xml   # 平板使用

在這個例子中,只有當前屏幕空間的最小可用寬度值為600dp時,你的平板layout才能夠被使用。

如果你還想進一步自定義你的UI,例如分別為7英寸和10英寸平板設計不同的layout,那麼你可以再補充額外的最小寬度值layout:

res/layout/main_activity.xml           # 手機使用 (小於600dp的可用寬度)
res/layout-sw600dp/main_activity.xml   # 7英寸平板使用(600dp或者更大的屏幕寬度)
res/layout-sw720dp/main_activity.xml   # 10英寸平板使用(720dp或者更大的屏幕寬度)

注意上面兩個例子中的資源所使用的最小寬度修飾符swdp,它所指的是不管當前設備的方向怎樣,屏幕寬高兩條邊中的最小寬度。因此,使用swdp從總體上忽略了屏幕的方向並為你的layout指定屏幕的可用尺寸是一種比較方便的方法。

然而,在一些情況下,分辨當前可用寬度或者高度對你的UI非常重要。例如,如果你有一個內置兩個窗口的layout要顯示兩個邊靠邊的fragment,你可能就需要根據當前屏幕的寬度是否大於等於600dp,以及是否橫向還是豎向才能決定是否使用這個layout。這種情況下,你的資源文件應該類似下面:

res/layout/main_activity.xml         # 手機使用(可用寬度小於600dp)
res/layout-w600dp/main_activity.xml  # 多窗口 (任何可用寬度大於等於600dp的屏幕)

注意第二套資源使用的可用寬度修飾符是wdp。使用這種方法,有些設備由於屏幕方向的改變導致兩種layout都會使用到(例如屏幕在一個方向上可用寬度至少有600dp,而在另一個方向可用寬度小於600dp)。

如果可用高度才是你需要關注的點的話,你同樣也可以與上面一樣使用hdp修飾符。甚至,你還可以聯合wdphdp兩種修飾符一塊使用,如果你真的需要的話。。。

4.3 聲明支持的屏幕尺寸(Declaring screen size support)

一旦你為不同的屏幕尺寸實現了對應的layout後,在你的manifest文件中聲明你的應用程序所支持的屏幕也是同樣重要的。

相對於新的屏幕配置修飾符,Android 3.2也為manifest的 元素引入了新的屬性。

android:requiresSmallesWidthDp
聲明支持的最小屏幕寬度。最小寬度指的是屏幕空間(dp單位)上最短的邊能夠給你的應用程序最小的可用寬度,換句話說就是在屏幕兩條邊上最短的可用邊。因此,為了能讓設備兼容你的應用程序,設備的最小寬度應該等於或者大於聲明的這個值。(通常聲明的這個“最小寬度”值指的是你的layout所支持的值,並且不管當前屏幕是什麼方向。)
例如,如果你的應用程序只支持最小可用寬度為600dp的平板設備:

    
    ...

然而,如果你的應用程序支持Android所支持的所有屏幕(比如小到426dpx320dp),那麼你可以不用聲明這個屬性,因為你的應用程序支持的最小寬度已經覆蓋了可能遇到的最小設備了。

慎重: Android系統並不會注意這個屬性,因此在運行的過程中這個屬性並不會對應用程序的行為產生任何影響。它的作用是在像Google Paly這樣的服務中過濾你的應用程序。不過,Google Play當前並不支持這個屬性過濾(在Android 3.2版本上)。因此如果你的應用程序不支持小屏幕,你還需要繼續使用其它關於尺寸的屬性。

android:compatibleWidthLimitDp
這個屬性允許你通過指定你的應用程序所支持的最大的“最小寬度”值來啟用屏幕兼容模式作為一個可選的功能。如果設備屏幕的最小邊可用寬度值大於你聲明的值,用戶依然能夠安裝你的應用程序,不過會在屏幕兼容模式下運行。默認情況下,屏幕兼容模式是關閉的,你的layout通常會被拉伸來填充屏幕。不過在系統欄會有一個按鈕允許用戶開啟或者關閉屏幕兼容模式。

注意: 如果你的layout能夠在大屏幕上正確的調整大小,那麼你不需要使用這個屬性。我們建議你避免使用這個屬性,你應該遵從本文檔提到的其它方法來確保你的layout尺寸能夠適配大屏幕。

android:largestWidthLimitDp
這個屬性允許你通過指定你的應用程序支持的最大的“最小寬度”值來強制啟用屏幕兼容模式。如果設備可用屏幕的最小邊大於你聲明的值,你的應用程序將會在屏幕兼容模式下運行,並且沒有任何途徑關閉兼容模式。

注意: 如果你的應用程序layout能夠在大屏幕上正確調整大小,那麼你不需要使用這個屬性。我們建議你避免使用這個屬性,你應該遵從本文檔提到的其它方法來確保你的layout尺寸能夠適配大屏幕。

慎重: 當為Android 3.2或者更高版本系統開發應用程序時,你不應該使用舊的屏幕尺寸屬性與上面列出的屬性組合使用。同時組合使用新的屬性和舊的尺寸屬性可能會導致無法預料到到結果。

更多關於這些屬性的信息,請參考上面列出的相關鏈接。

 

最佳實踐(Best Practices)


支持多樣屏幕的目的是為了創建能夠正常運行,並且在Android支持的通用屏幕設備上都能顯示良好的應用程序。本文前面的章節闡述了Android如何適配你的應用程序到不同的屏幕配置上,以及你可以怎樣為應用程序在不同的屏幕配置上定制不同的效果。本章節主要提供一些額外的小貼士,以及關於確保你的應用程序在不同屏幕配置上都能良好縮放這種技術的概要。

下面是確保你的應用程序能夠在不同屏幕上良好顯示的快速檢查列表:

在XML layout文件中指定尺寸時要使用wrap_contentfill_parent或者dp單位。

不要在你的應用程序代碼中使用固定的像素值。

不要使用AbsoluteLayout(已經被廢棄)

為不同的屏幕密度提供可替代的圖片資源。

下面的章節提供更多的細節。

5.1 為layout的尺寸使用wrap_content、fill_content或者dp單位

當在XML layout文件中定義view的android:layout_widthandroid:layout_height時,使用wrap_contentfill_parent或者dp單位來確保view在當前設備屏幕上能夠分配到一個合適的尺寸。

例如,一個view定義了layout_width=100dp,那麼它在medium密度屏幕上將有100像素寬,而在high密度的屏幕上系統會將它放大到150像素寬,這樣view就在屏幕上占據大約相等物理尺寸。

同樣的,你應該使用sp(獨立尺度像素)單位來定義字體的尺寸。sp的縮放因子由用戶設定,系統會像處理dp一樣縮放這些尺寸。

5.2 不要在應用程序的代碼中寫死像素值

出於性能原因以及為了保持代碼的簡單性,Android系統使用像素作為尺寸和坐標值的標准單位。這意味著一個view的尺寸在代碼中都是用像素單位來表示,並且基於當前屏幕密度而變化。例如,如果myView.getWidth()返回值為10,這表示在當前屏幕上myView寬度為10像素,但是在更高密度的屏幕上,這個返回值可能為15像素。如果你在應用程序的代碼中使用像素值來定義圖片的尺寸,這會導致圖片無法根據當前屏幕密度進行預縮放處理,你可能需要在自己的代碼中自行縮放這些像素值來適配未經縮放的原圖。

如果你的應用程序需要在運行時操作圖片或者處理像素值,請參考下面Additional Density Consideration章節。

5.3 不要使用AbsoluteLayout

不像其它的layout控件,AbsoluteLayout強制使用固定的值來給子view布局,這樣就導致在不同屏幕上很容易出現布局問題。因此,AbsoluteLayout在Android 1.5(API Level 3)就給廢棄了。

你應該替換使用RelativeLayout,它能夠根據相對位置給子view布局。例如,你可以指定一個按鈕應該顯示在一個TextView的右邊。

5.4 使用尺寸和密度相關的資源

盡管系統會根據當前屏幕配置自動縮放你的layout和圖片資源,但你可能需要調整UI在不同屏幕上的尺寸,以及為不同的屏幕密度提供對應的圖片資源。這其實是重申上面章節講的內容。

如果你需要控制你的應用程序在各個屏幕上的顯示效果,你需要在特定資源文件夾中調整你的layout和圖片資源。例如,考慮到一個圖標需要在medium和high屏幕密度上顯示,你可以簡單的創建兩個不同尺寸的圖標(例如medium密度為100x100尺寸,high密度為150x150尺寸),然後分別將這個兩個圖標放到特定修飾符的資源文件夾中:

res/drawable-mdpi/icon.png   //for medium-density screens
res/drawable-hdpi/icon.png   //for high-density screens

注意: 如果一個資源文件夾的名字沒有定義密度修飾符,那麼系統會認為這個資源文件夾中的資源是為medium這個密度基准而設計的,並且在需要的情況下會為其它密度縮放這些資源。

更多關於有效配置修飾符的內容,請參考上面使用配置修飾符(Using configuration qualifiers)章節。

 

其它密度注意事項(Additional Density Considerations)


本章節將闡述更多關於Android如何在不同屏幕密度上縮放圖片資源,以及如何更進一步控制圖片在不同密度屏幕上的繪制。本章節的內容對於大部分應用程序來說不是那麼重要,除非你的應用程序在不同屏幕密度上運行遇到問題,或者你的應用程序需要操作圖形。

為了更好的理解在運行過程中是如何操作圖形來支持多種密度屏幕,你應該先理解系統用於確保正確縮放圖片的途徑:

預縮放資源(例如圖片資源)
基於當前屏幕的密度,系統使用你的應用程序提供的指定尺寸或密度修飾符的資源直接顯示。如果提供的資源與當前屏幕密度不符合,系統將會加載默認的資源並放大或縮小這些資源來適配當前的屏幕密度。系統會假設默認的資源(就是那些保存在沒有添加任何配置修飾符資源文件夾中的資源)是為屏幕密度的基准(mdpi)而設計的,除非系統加載的資源是從其它密度修飾符資源文件中加載的。所謂的預縮放就是系統將圖片大小調整到適合當前屏幕尺寸時做的處理。 如果你需要獲取預縮放資源的尺寸,系統返回的將是縮放之後的資源尺寸。例如,一張為mdpi屏幕設計的圖片為50x50像素,它將會在hdpi屏幕上放大到75x75像素(如果沒有對應的hdpi資源替換的話),並且系統返回的尺寸也將是放大後的這個值。
在一些情況下,你可能不希望Android系統進行預縮放資源處理。避免預縮放處理最簡單的方法就是把資源放到nodpi配置修飾符的資源文件夾下。例如:
res/drawable-nodpi/icon.png
當系統從這個文件夾中獲取icon.png資源時,系統會不根據當前設備密度對這張圖片進行縮放。

自動縮放像素尺寸和位置
應用程序可以通過在manifest文件中設置android:anyDensity屬性為false,或者在程序代碼中把一張圖片的Bitmap對象的inScaled屬性設置為false來禁用預縮放處理。在這種情況下,系統將會在繪制過程中自動縮放絕對像素位置和像素尺寸。系統通過這麼處理來保證使用像素定義的屏幕元素與在基准屏幕密度(mdpi)上顯示的物理尺寸保持大致相同。系統所做的這些縮放處理對於應用程序來說是透明,應用程序獲取到的也是縮放後的尺寸,而不是實際的物理像素尺寸。
例如,假設一台設備是WVGA high密度的屏幕,它的分辨率為480x800並且與傳統的HVGA屏幕的大小一樣,現在它運行一個禁用預縮放處理的程序。在這種情況下,當應用程序請求屏幕尺寸時,系統將會“欺騙”應用程序,返回320x533尺寸(近似mdpi的屏幕密度)。之後,當應用程序執行繪畫操作時,例如廢除一個位於(10,10)到(100,100)的矩形,系統將會適當轉換這個位置的值,實際上廢除的區域為(15,15)到(150,150)。如果你的應用程序需要直接操作圖片的縮放,這個誤差可能會導致意想不到的結果,不過這是盡可能考慮應用程序的性能後得出的一個合理的方案。如果你遇到這種情況,請參考下面將dp單位轉換為像素單位(Converting dp units to pixel units)
通常情況下,你不應該禁用預縮放處理。支持多樣屏幕的最好方法是遵從上面如何支持多屏幕(How to Support Multiple Screens) 章節提及的基本技術。

如果你的應用程序需要操作圖片或者需要通過其它方式在屏幕上直接與像素進行交互,那你可能需要采取額外的步驟來支持不同的屏幕密度。例如,如果你需要根據手指在屏幕上劃過的像素點來識別觸摸手勢並進行響應,你就需要采用適當的密度無關像素值來取代實際像素值。

6.1 縮放運行過程中創建的Bitmap對象(Scaling Bitmap objects created at runtime)

如果你的應用程序在內存中創建一張圖片(一個Bitmap對象),默認情況下系統會假設這張圖片是為medium這個基准屏幕密度而設計的,並且在渲染的時候會自動縮放。當Bitmap沒有指定密度屬性時,系統會添加“自動縮放”屬性給Bitmap。如果你沒有正確計算當前設備的屏幕密度並且為Bitmap對象指定相應的密度屬性,自動縮放會跟你沒有提供可替換資源的處理方法一樣縮放這些Bitmap圖片。

為了控制運行過程中創建的Bitmap對象是否縮放,你可以通過Bitmap的setDensity()為其指定密度類型,該方法可選參數值為DisplayMetrics類中定義的常量,例如DENSITY_HIGH或者DENSITY_LOW

如果你是通過BitmapFactory從文件或者數據流這些數據源創建了Bitmap對象,那麼你可以當做這個Bitmap對象已經存在一樣,使用BitmapFactory.Options來設置bipmap對象的屬性,系統通過這些屬性來決定如何對它進行縮放。例如,你可以設置inDensity屬性來設置bitmap對象對應的屏幕密度,以及inScaled屬性來設置bitmap是否要通過縮放來適配當前設備屏幕密度。

如果你設置inScaled屬性為false,那麼你就禁用了系統可能會對bitmap進行的預縮放處理,系統在每次繪制的時候才對bitmap自動縮放處理。使用自動縮放來取代預處理會消耗更多的CPU,不過可以節省內存。

圖5

圖5: 對比預縮放和自動縮放的bitmap

圖5顯示了在high密度屏幕上分別加載low(120)、medium(160)、high(240)密度的bitmap時,預處理縮放和自動縮放機制的區別。可以看出其中的差異是很小的,因為所有的bitmap都被縮放到適配當前屏幕密度的大小,盡管被縮放的bitmap由於預縮放處理還是繪制時自動縮放處理而有小小的顯示差異。

注意: 在Android 3.0或更高的系統版本中,由於改進了圖形框架,預縮放或者自動縮放的bitmap顯示效果將看不出區別。

6.2 將dp單位轉換為像素單位(Converting dp units to pixel units)

在一些情況,你需要使用dp單位表達尺寸後再轉換為對應的像素單位。試想一下一個應用程序識別一個滑動或者劃動手勢的要求是手指至少移動16像素。在基准屏幕上要識別出這個手勢,用戶至少要滑動16 pixels/160dpi,相當於一英寸的十分之一(2.5mm)。如果是在high密度的設備屏幕上,用戶至少要滑動16 pixels/240dpi,相當於一英寸的十五分之一(1.7mm)。這個距離必須足夠短,這樣用戶才能感覺這個應用程序很靈敏。

為了解決這個問題,手勢的觸發距離必須在代碼中用dp表示,並轉換為對應的實際像素尺寸。例如:

// 用dp單位表示的手勢觸發距離
private static final float GESTURE_THRESHOLD_DP = 16.0f;

// 獲取屏幕密度
final float scale = getResources().getDisplayMetrics().density;
// 基於屏幕密度將dp尺寸轉換為px尺寸
mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);

// 使用mGestureThreshold作為手勢距離判定尺寸...

其中DisplayMetrics.density屬性是根據當前屏幕密度得出的縮放因子,你必須使用這個因子轉換dp單位和像素單位。在medium密度的屏幕上,DisplayMetrics.density等於1.0;在high密度的屏幕上等於1.5;在extra-high密度的屏幕上等於2.0;在low密度的屏幕上等於0.75。你必須使用這個因子的數值乘以dp單位值得出在當前屏幕上對應的實際像素尺寸(額外增加0.5f是為了在強制轉換為整數時得到較大的整數值)。更多信息,請參考DisplayMetrics類。

另外,與其隨意為這類事件定義一個觸發值,你應該使用ViewConfiguration類中的可用方法獲取預縮放的配置值。

6.3 使用預縮放配置值(Using pre-scaled configuration values)

你可以使用ViewConfiguration類來獲取Android系統使用的距離值、速度值、時間值等等。例如,系統框架識別滑動操作的像素距離值可以使用getScaledTouchSlop()方法獲取:

private static final int GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).getScaledTouchSlop();

使用ViewConfiguration類中以getScaled開頭的方法返回的像素值,不管當前是什麼屏幕密度,都保證能正確顯示。

 

如何在多種多樣的屏幕上測試你的應用程序(How to Test Your Application on Multiple Screens)


在發布你的應用程序之前,你應該在所有支持的屏幕尺寸和屏幕密度上進行完整測試。Android SDK中包含了很多你可以使用的仿真模擬器,這些模擬器模擬出了通用屏幕配置的尺寸和密度,而你的應用程序很可能就會在這種環境中運行。你同樣可以修改仿真模擬器的默認尺寸、密度和分辨率,以模擬出一些特別屏幕的屬性。使用仿真模擬器和額外的自定義配置就能測試一些可能的屏幕配置,因此你沒有必要為了測試你的應用程序而去購買每一種設備。

配置應用程序多樣屏幕支持性測試環境,你需要創建一系列AVD(Android虛擬機),可以使用默認的仿真模擬器或者創建符合你的應用程序能夠支持的屏幕尺寸密度的屏幕配置。為此,你可以使用AVD管理器來創建這些AVD,並通過圖形界面啟動它們。

圖6

圖6: 為測試屏幕支持個的系列AVD

啟動Android SDK管理器,在window平台下你可以執行Android SDK文件夾下的SDK Manager.exe文件,在其它平台上可以執行/tools/目錄下的android可執行文件。圖6展示了選中一個AVD的AVD管理器,用於測試各種各樣的屏幕配置。

表3展示了Android SDK提供的各種各樣仿真模擬器,你可以使用這些模擬器來模擬一些常見的屏幕配置。

表3: Android SDK提供的仿真器及各種屏幕配置(粗體顯示),還有其它一些典型分辨率。

Low密度(120),ldpi Medium密度(160),mdpi High密度(240),hdpi Extra-high密度(320),xhdpi Small屏幕 QVGA(240x320)   480x640 Normal屏幕 WQVGA400(240x400)
WQVGA432(240x432)
HVGA(320x480) WVGA800(480x800)
WVGA854(480x854)

600x1024 Large屏幕 WVGA800(480x800)[1]
WVGA854(480x854)[1]
WVGA800(480x800)[2]
WVGA854(480x854)[2]
  Extra-Large屏幕 1024x600 WXGA(1280x800)[3]
1024x768
1280x768 1536x1152
1920x1152
1920x1200

[1] 模擬這個配置,在創建AVD的時候要自定義120的密度,並且選擇WVGA800或者WVGA854的皮膚
[2] 模擬這個配置,在創建AVD的時候要自定義160的密度,並且選擇WVGA800或者WVGA854的皮膚
[3] Android 3.0平台上才支持這個皮膚

更多關於創建和使用AVD測試應用程序的內容情況請參考Managing AVDs with AVD Manager。

查看所有支持的屏幕配置激活設備比例,請參考Screen Sizes and Densities。

我們同樣建議你將模擬器的物理尺寸配置成與真實設備尺寸相近後再測試你的應用程序。這樣更容易將模擬結果與各個尺寸和密度比較。為此,你需要知道你的計算機顯示器大致的dpi密度(例如,一個30英寸的戴爾顯示器密度大概96dpi)。當你從AVD管理器中啟動AVD的時候,你可以在啟動選項中指定模擬器的屏幕尺寸和顯示器的dpi,如圖7:

圖7

圖7 從AVD管理器中啟動AVD時,你可以設置的尺寸和密度選項

如果你想要在內建模擬器皮膚支持的分辨率或密度之外的屏幕上測試你的應用程序,你可以通過自定義分辨率和密度來創建一個AVD。當使用AVD管理器創建AVD的時候不要選擇內建的皮膚,自己指定分辨率。

如果你使用命令行啟動你的AVD,你可以通過-scale選項為模擬器指定縮放因子,例如:

emulator -avd  -scale 96dpi

為了精簡模擬器的尺寸,你也可以為-scale選項傳遞一個0.1到3之間的數值,它代表期望的縮放因子。

更多關於從命令行創建AVD模擬器的內容,請參考Managing AVDs from the Command Line。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved