由於 Android 系統的開放性,任何用戶、開發者、OEM 廠商、運營商都可以對 Android 進行定製,於是導致:
Android 系統碎片化: 小米定製的 MIUI、魅族定製的 flyme、華爲定製的 EMUI 等等——當然都是基於 Google 原生系統定製的;
Android 機型屏幕尺寸碎片化: 5 寸、5.5 寸、6 寸等等;
Android 屏幕分辨率碎片化: 320x480、480x800、720x1280、1080x1920。
據友盟指數顯示,統計至 2015 年 12 月,支持 Android 的設備共有 27796 種。當 Android 系統、屏幕尺寸、屏幕密度出現碎片化的時候,就很容易出現同一元素在不同手機上顯示不同的問題。
雖然系統爲使您的應用適用於不同的屏幕,會進行縮放和大小調整,但您應針對不同的屏幕尺寸和密度優化應用。
這樣可以最大程度優化所有設備上的用戶體驗,用戶會認爲您的應用實際上是專爲他們的設備而設計,而不是簡單地拉伸以適應其設備屏幕。
二、相關概念
1. 屏幕尺寸
含義:按屏幕對角測量的實際物理尺寸。
爲簡便起見,Android 將所有實際屏幕尺寸分組爲四種通用尺寸:小、 正常、大和超大
單位:英寸(inch),一英寸≈2.54cm
2. 分辨率
含義:手機在橫向、縱向上的像素點數總和
一般描述成屏幕的”寬 x 高”=AxB
含義:屏幕在橫向方向(寬度)上有 A 個像素點,在縱向方向(高)有 B 個像素點。
例子:1080x1920,即寬度方向上有 1080 個像素點,在高度方向上有 1920 個像素點
單位:px(pixel),1px=1 像素點
UI 設計師的設計圖會以 px 作爲統一的計量單位。
Android 手機常見的分辨率:320x480、480x800、720x1280、1080x1920
3. 屏幕像素密度
含義:每英寸的像素點數
單位:dpi(dots per ich)
假設設備內每英寸有 160 個像素,那麼該設備的屏幕像素密度=160dpi
安卓手機對於每類手機屏幕大小都有一個相應的屏幕像素密度:
密度類型 | 代表的分辨率(px) | 屏幕像素密度(dpi) |
---|---|---|
低密度(ldpi) | 240x320 | 120 |
中密度(mdpi) | 320x480 | 160 |
高密度(hdpi) | 480x800 | 240 |
超高密度(xhdpi) | 720x1280 | 320 |
超超高密度(xxhdpi) | 1080x1920 | 480 |
4. 屏幕尺寸、分辨率、像素密度三者關係
一部手機的分辨率是寬 x 高,屏幕大小是以寸爲單位,那麼三者的關係是:
5. 密度無關像素 (dp)
含義:density-independent pixel,叫 dp 或 dip,與終端上的實際物理像素點無關。
單位:dp,可以保證在不同屏幕像素密度的設備上顯示相同的效果
Android 開發時用 dp 而不是 px 單位設置圖片大小,是 Android 特有的單位
場景:假如同樣都是畫一條長度是屏幕一半的線,如果使用 px 作爲計量單位,那麼在 480x800 分辨率手機上設置應爲 240px;在 320x480 的手機上應設置爲 160px,二者設置就不同了;如果使用 dp 爲單位,在這兩種分辨率下,160dp 都顯示爲屏幕一半的長度。
dp 與 px 的轉換
因爲 UI 設計師給你的設計圖是以 px 爲單位的,Android 開發則是使用 dp 作爲單位的,那麼我們需要進行轉換:
密度類型 | 代表的分辨率(px) | 屏幕像素密度(dpi) | 換算(px/dp) | 比例 |
---|---|---|---|---|
低密度(ldpi) | 240x320 | 120 | 1dp=0.75px | 3 |
中密度(mdpi) | 320x480 | 160 | 1dp=1px | 4 |
高密度(hdpi) | 480x800 | 240 | 1dp=1.5px | 6 |
超高密度(xhdpi) | 720x1280 | 320 | 1dp=2px | 8 |
超超高密度(xxhdpi) | 1080x1920 | 480 | 1dp=3px | 12 |
在 Android 中,規定以 160dpi(即屏幕分辨率爲 320x480)爲基準:1dp=1px
6. 獨立比例像素
含義:scale-independent pixel,叫 sp 或 sip
單位:sp
Android 開發時用此單位設置文字大小,可根據字體大小首選項進行縮放。
推薦使用 12sp、14sp、18sp、22sp 作爲字體設置的大小,不推薦使用奇數和小數,容易造成精度的丟失問題;小於 12sp 的字體會太小導致用戶看不清。
三、如何適配
1. 佈局適配
使用相對佈局(RelativeLayout),禁用絕對佈局(AbsoluteLayout)
開發中,我們使用的佈局一般有:
線性佈局(Linearlayout)
相對佈局(RelativeLayout)
幀佈局(FrameLayout)
絕對佈局(AbsoluteLayout)
由於絕對佈局(AbsoluteLayout)適配性極差,所以極少使用。
對於線性佈局(Linearlayout)、相對佈局(RelativeLayout)和幀佈局(FrameLayout)需要根據需求進行選擇,但要記住:
相對佈局 RelativeLayout
佈局的子控件之間使用相對位置的方式排列,因爲 RelativeLayout 講究的是相對位置,即使屏幕的大小改變,視圖之前的相對位置都不會變化,與屏幕大小無關,靈活性很強
線性佈局 LinearLayout
通過多層嵌套 LinearLayout 和組合使用“wrap_content”和“match_parent”已經可以構建出足夠複雜的佈局。但是 LinearLayout 無法準確地控制子視圖之間的位置關係,只能簡單的一個挨着一個地排列。
所以,對於屏幕適配來說,使用相對佈局(RelativeLayout)將會是更好的解決方案。
根據屏幕的配置來加載相應的 UI 佈局
最小寬度(Smallest-width)限定符
在 Android 3.2 及之後版本,引入了最小寬度(Smallest-width)限定符
定義:通過指定某個最小寬度(以 dp 爲單位)來精確定位屏幕從而加載不同的 UI 資源
使用場景:
你需要爲標準 7 英寸平板電腦匹配雙面板佈局(其最小寬度爲 600 dp),在手機(較小的屏幕上)匹配單面板佈局
解決方案:您可以使用上文中所述的單面板和雙面板這兩種佈局,但您應使用 sw600dp 指明雙面板佈局僅適用於最小寬度爲 600 dp 的屏幕,而不是使用 large 尺寸限定符。
sw xxxdp,即 small width 的縮寫,其不區分方向,即無論是寬度還是高度,只要大於 xxxdp,就採用次此佈局
例子:使用了 layout-sw 600dp 的最小寬度限定符,即無論是寬度還是高度,只要大於 600dp,就採用 layout-sw 600dp 目錄下的佈局
代碼展示:
(1)適配手機的單面板(默認)佈局: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>
(2)適配尺寸>7 寸平板的雙面板佈局: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>
對於最小寬度≥ 600 dp 的設備,系統會自動加載 layout-sw600dp/main.xml(雙面板)佈局,否則系統就會選擇 layout/main.xml(單面板)佈局(這個選擇過程是 Android 系統自動選擇的)
2. 佈局組件適配
本質:使得佈局組件自適應屏幕尺寸
做法
使用”wrap_content”、”match_parent”和”weight“來控制視圖組件的寬度和高度。
“wrap_content”:相應視圖的寬和高就會被設定成所需的最小尺寸以適應視圖中的內容
“match_parent”(在 Android API 8 之前叫作”fill_parent”):視圖的寬和高延伸至充滿整個父佈局
“weight”
- 定義:是線性佈局(Linelayout)的一個獨特比例分配屬性
- 作用:使用此屬性設置權重,然後按照比例對界面進行空間的分配,公式計算是:控件寬度=控件設置寬度+剩餘空間所佔百分比寬幅
通過使用”wrap_content”、”match_parent”和”weight”來替代硬編碼的方式定義視圖大小&位置,你的視圖要麼僅僅使用了需要的那邊一點空間,要麼就會充滿所有可用的空間,即按需佔據空間大小,能讓你的佈局元素充分適應你的屏幕尺寸。
3. 圖片資源適配
本質:使得圖片資源在不同屏幕密度上顯示相同的像素效果
做法:使用自動拉伸位圖:Nine-Patch 的圖片類型
假設需要匹配不同屏幕大小,你的圖片資源也必須自動適應各種屏幕尺寸
使用場景:一個按鈕的背景圖片必須能夠隨着按鈕大小的改變而改變。
使用普通的圖片將無法實現上述功能,因爲運行時會均勻地拉伸或壓縮你的圖片
解決方案:使用自動拉伸位圖(nine-patch 圖片),後綴名是.9.png,它是一種被特殊處理過的 PNG 圖片,設計時可以指定圖片的拉伸區域和非拉伸區域;使用時,系統就會根據控件的大小自動地拉伸你想要拉伸的部分。
必須要使用.9.png 後綴名,因爲系統就是根據這個來區別 nine-patch 圖片和普通的 PNG 圖片的;
當你需要在一個控件中使用 nine-patch 圖片時,如
android:background=”@drawable/button”系統就會根據控件的大小自動地拉伸你想要拉伸的部分
4. 進行屏幕密度匹配
“佈局控件”匹配
本質:使得佈局組件在不同屏幕密度上顯示相同的像素效果
做法:使用密度無關像素
由於各種屏幕的像素密度都有所不同,因此相同數量的像素在不同設備上的實際大小也有所差異,這樣使用像素(px)定義佈局尺寸就會產生問題。
因此,請務必使用密度無關像素 dp 或獨立比例像素 sp 單位指定尺寸。
相關概念介紹:
(1)密度無關像素
含義:density-independent pixel,叫 dp 或 dip,與終端上的實際物理像素點無關。
單位:dp,可以保證在不同屏幕像素密度的設備上顯示相同的效果
Android 開發時用 dp 而不是 px 單位設置圖片大小,是 Android 特有的單位
場景:假如同樣都是畫一條長度是屏幕一半的線,如果使用 px 作爲計量單位,那麼在 480x800 分辨率手機上設置應爲 240px;在 320x480 的手機上應設置爲 160px,二者設置就不同了;如果使用 dp 爲單位,在這兩種分辨率下,160dp 都顯示爲屏幕一半的長度。
dp 與 px 的轉換
因爲 ui 給你的設計圖是以 px 爲單位的,Android 開發則是使用 dp 作爲單位的,那麼該如何轉換呢?
密度類型 | 代表的分辨率(px) | 屏幕像素密度(dpi) | 換算(px/dp) | 比例 |
---|---|---|---|---|
低密度(ldpi) | 240x320 | 120 | 1dp=0.75px | 3 |
中密度(mdpi) | 320x480 | 160 | 1dp=1px | 4 |
高密度(hdpi) | 480x800 | 240 | 1dp=1.5px | 6 |
超高密度(xhdpi) | 720x1280 | 320 | 1dp=2px | 8 |
超超高密度(xxhdpi) | 1080x1920 | 480 | 1dp=3px | 12 |
在 Android 中,規定以 160dpi(即屏幕分辨率爲 320x480)爲基準:1dp=1px
T-Mobile G1(第一款 android 手機)的參數屬於 mdpi 區域的,以上就是取 160dpi 作爲基準的原因。
(2)獨立比例像素
含義:scale-independent pixel,叫 sp 或 sip
單位:sp
Android 開發時用此單位設置文字大小,可根據用戶的偏好文字大小/字體大小首選項進行縮放
推薦使用 12sp、14sp、18sp、22sp 作爲字體設置的大小,不推薦使用奇數和小數,容易造成精度的丟失問題;小於 12sp 的字體會太小導致用戶看不清
所以,爲了能夠進行不同屏幕像素密度的匹配,我們推薦:
使用 dp 來代替 px 作爲控件長度的統一度量單位
使用 sp 作爲文字的統一度量單位
可是,請看以下一種場景:
Nexus5 的總寬度爲 360dp,我們現在在水平方向上放置兩個按鈕,一個是 150dp 左對齊,另外一個是 200dp 右對齊,那麼中間留有 10dp 間隔;但假如同樣地設置在 Nexus S(屏幕寬度是 320dp),會發現,兩個按鈕會重疊,因爲 320dp<200+150dp
從上面可以看出,由於 Android 屏幕設備的多樣性,如果使用 dp 來作爲度量單位,並不是所有的屏幕的寬度都具備相同的 dp 長度
再次明確,屏幕寬度和像素密度沒有任何關聯關係
所以說,dp 解決了同一數值在不同分辨率中展示相同尺寸大小的問題(即屏幕像素密度匹配問題),但卻沒有解決設備尺寸大小匹配的問題。(即屏幕尺寸匹配問題)
當然,我們一開始討論的就是屏幕尺寸匹配問題,使用 match_parent、wrap_content 和 weight,儘可能少用 dp 來指定控件的具體長寬,大部分的情況我們都是可以做到適配的。
“圖片資源”匹配
本質:使得圖片資源在不同屏幕密度上顯示相同的像素效果
做法:提供備用位圖(符合屏幕尺寸的圖片資源)
由於 Android 可在各種屏幕密度的設備上運行,因此我們提供的位圖資源應該始終可以滿足各類密度的要求:
密度類型 | 代表的分辨率(px) | 屏幕像素密度(dpi) |
---|---|---|
低密度(ldpi) | 240x320 | 120 |
中密度(mdpi) | 320x480 | 160 |
高密度(hdpi) | 480x800 | 240 |
超高密度(xhdpi) | 720x1280 | 320 |
超超高密度(xxhdpi) | 1080x1920 | 480 |
步驟 1:根據以下尺寸範圍針對各密度生成相應的圖片。
比如說,如果我們爲 xhdpi 設備生成了 200x200 px 尺寸的圖片,就應該按照相應比例地爲 hdpi、mdpi 和 ldpi 設備分別生成 150x150、100x100 和 75x75 尺寸的圖片:
即一套分辨率=一套位圖資源(這個當然是 Ui 設計師做了)
步驟 2:將生成的圖片文件放在 res/ 下的相應子目錄中(mdpi、hdpi、xhdpi、xxhdpi),系統就會根據運行您應用的設備的屏幕密度自動選擇合適的圖片。
步驟 3:通過引用 @drawable/id,系統都能根據相應屏幕的 屏幕密度(dpi)自動選取合適的位圖。
如果是.9 圖或者是不需要多個分辨率的圖片,放在 drawable 文件夾即可
對應分辨率的圖片要正確的放在合適的文件夾,否則會造成圖片拉伸等問題。
更好的方案解決“圖片資源”適配問題
上述方案是常見的一種方案,這固然是一種解決辦法,但缺點在於:
每套分辨率出一套圖,爲美工或者設計增加了許多工作量
對 Android 工程文件的 apk 包變的很大
那麼,有沒有一種方法:
保證屏幕密度適配
可以最小佔用設計資源
使得 apk 包不變大(只使用一套分辨率的圖片資源)
方法介紹
先來理解下 Android 加載資源過程:
Android SDK 會根據屏幕密度自動選擇對應的資源文件進行渲染加載(自動渲染)。比如說,SDK 檢測到你手機的分辨率是 320x480(dpi=160),會優先到 drawable-mdpi 文件夾下找對應的圖片資源;但假設你只在 xhpdi 文件夾下有對應的圖片資源文件(mdpi 文件夾是空的),那麼 SDK 會去 xhpdi 文件夾找到相應的圖片資源文件,然後將原有大像素的圖片自動縮放成小像素的圖片,於是大像素的圖片照樣可以在小像素分辨率的手機上正常顯示。
具體請看:http://blog.csdn.net/xiebudong/article/details/37040263
所以理論上來說只需要提供一種分辨率規格的圖片資源就可以了。
那麼應該提供哪種分辨率規格呢?
如果只提供 ldpi 規格的圖片,對於大分辨率(xdpi、xxdpi)的手機如果把圖片放大就會不清晰。所以需要提供一套你需要支持的最大 dpi 分辨率規格的圖片資源,這樣即使用戶的手機分辨率很小,這樣圖片縮小依然很清晰。
那麼這一套最大 dpi 分辨率規格應該是哪種呢?是現在市面手機分辨率最大可達到 1080X1920 的分辨率(dpi=xxdpi=480)嗎?
xhdpi 應該是首選。原因如下:
xhdpi 分辨率以內的手機需求量最旺盛:目前市面上最普遍的高端機的分辨率還多集中在 720X1080 範圍內(xhdpi),所以目前來看 xhpdi 規格的圖片資源成爲了首選。
節省設計資源&工作量:在現在的 App 開發中(iOS 和 Android 版本),有些設計師爲了保持 App 不同版本的體驗交互一致,可能會以 iPhone 手機爲基礎進行設計,包括後期的切圖之類的。
設計師們一般都會用最新的 iPhone6 和 iPhone5s(5s 和 5 的尺寸以及分辨率都一樣)來做原型設計,所有參數請看下方:
機型 | 分辨率(px) | 屏幕尺寸(inch) | 系統密度(dpi) |
---|---|---|---|
iPhone 5s | 640X1164 | 4 | 332 |
iPhone 6 | 1334x750 | 4.7 | 326 |
iPhone 6 Plus | 1080x1920 | 5 | 400 |
iPhone 主流的屏幕 dpi 約等於 320, 剛好屬於 xhdpi,所以選擇 xhdpi 作爲唯一一套 dpi 圖片資源,可以讓設計師不用專門爲 Android 端切圖,直接把 iPhone 的那一套切好的圖片資源放入 drawable-xhdpi 文件夾裏就好,這樣大大減少的設計師的工作量!