Android屏幕適配一直是Android開發們的一個痛點,各種各樣的屏幕分辨率等,對Android的屏幕適配帶來了很大的麻煩,而谷歌的解決方案也并不被所有人滿意,所以筆者結合Android官方文檔,來談談這個話題。
術語和基本概念
本節介紹Android屏幕單位等的一些基本概念。
屏幕尺寸
官方文檔的解釋是:
按屏幕對角測量的實際物理尺寸。 為簡便起見,Android 將所有實際屏幕尺寸分組為四種通用尺寸:小、 正常、大和超大。
屏幕尺寸是指屏幕的物理尺寸大小,Android使用samll,normal,large,xlarge作為屏幕尺寸的限定符(3.2之后推薦使用sw<N>dp等來適配屏幕大小)。
屏幕密度
屏幕物理區域中的像素量,屏幕密度的單位是dpi(每英寸點數),粗略來說,屏幕密度越高的手機,看起來越清晰,我們通常放多組圖片就是根據屏幕密度來劃分的,Android將屏幕密度分為低、中、高、超高、超超高和超超超高,用字母表示是ldpi,mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi。
分辨率
分辨率是指屏幕寬高的像素值。
密度無關像素
官方文檔的解釋是:
在定義 UI 布局時應使用的虛擬像素單位,用于以密度無關方式表示布局維度 或位置。
密度無關像素等于 160 dpi 屏幕上的一個物理像素,這是 系統為“中”密度屏幕假設的基線密度。在運行時,系統 根據使用中屏幕的實際密度按需要以透明方式處理 dp 單位的任何縮放 。dp 單位轉換為屏幕像素很簡單: px = dp * (dpi / 160)。 例如,在 240 dpi 屏幕上,1 dp 等于 1.5 物理像素。在定義應用的 UI 時應始終使用 dp 單位 ,以確保在不同密度的屏幕上正常顯示 UI。
典型手機的屏幕
先看dp和px的信息:
dpi | ?px=1dp | |
---|---|---|
ldpi | 120dpi | 0.75 |
mdpi | 160dpi | 1 |
hdpi | 2400dpi | 1.5 |
xhdpi | 320dpi | 2 |
xxhdpi | 480dpi | 3 |
xxxhdpi | 640dpi | 4 |
也就是說,屏幕像素密度越高的手機,1dp轉換的像素數越大,成正比。 知道了dp的px轉換,那么,Google引入dp來代替px究竟有什么用處呢?dp究竟是什么值呢? 看這個問題就要先看dpi,dpi是每英寸像素數,而dp與px的轉換是與dpi成正比的,那么,對于一個dpi是x的手機來說,每英寸對應xpx,而對于這個手機來說,(x/160)px=1dp,那么每英寸對應x(160/x)dp=160dp。所以dp實際上反應的是實際的物理尺寸,和屏幕的分辨率,屏幕的像素密度等都無關。
Google推薦適配方案
了解了這些基本概念后,那么我們試著去理解Google的屏幕適配理念。首先,對用戶來說,相同物理大小的屏幕肯定是一樣的布局更好,而不該受限于屏幕的像素密度,所以Google用dp來解決這個問題,使用dp作為長度的單位,并配合Android的提供資源方案,能做到在相同物理大小的屏幕上有相同的布局。那么對于不同物理大小的屏幕,Google推薦對不同的屏幕進行專門的適配,而不是對布局進行簡單的拉伸。
按比例適配方案
Google的方案固然是好,可是我們在做快速開發的時候,并不可能在屏幕的適配上下這么大的功夫,那有沒有辦法讓所有屏幕的布局按比例看起來都是一樣的呢。。。鴻洋的文章Android 屏幕適配方案給出了一個這樣的方案。大致就是,根據UI給的切圖,通過Java代碼生成values文件,把所有的像素值替換成其余屏幕上的像素值。 例如UI切圖是480320的分辨率,那么: 寬度為320,將任何分辨率的寬度分為320份,取值為x1-x320; 高度為480,將任何分辨率的高度分為480份,取值為y1-y480。 對于800480的寬度480:
這么做是不是就完全沒問題呢?
- 我們做頭像的ImageView一般是正方形的,在上例中,UI給的切圖可能是40*40像素的,我們就在布局中寫x40*y40,可是其不不能保證在所有屏幕中都是正方形的。例如對于800*480的屏幕,x40=66.7px,y40=60px,這時候顯示在屏幕上的就不是正方形的了。
- 使用px去適配是偏離Google的適配方案的,那么對于小屏幕高dpi的手機,Android會選擇高精度圖片,而由于屏幕小導致分辨率也不高,實際顯示的像素可能低于選用的圖片,造成內存的浪費(此時常規方式寫的界面一般也會有適配問題)。也就是說Android的資源選取方案“不好用”了。
適配建議
以下是Google給的屏幕適配建議:
- 在 XML 布局文件中指定尺寸時使用 wrap_content、match_parent 或 dp 單位;
- 不要在應用代碼中使用硬編碼的像素值;
- 不要使用 AbsoluteLayout(已棄用);
- 為不同屏幕密度提供替代位圖可繪制對象;
對于UI的切圖,我們將其像素轉換為dp寫界面時,在xml文件中盡量不要使用較大的dp值,例如
android:layout_marginRight="200dp"
,使用android:layout_alignParentRight="true" android:layout_marginRight="30dp"
替代,因為200dp占屏幕的百分比更大,在不同屏幕下差異會比較大,對于寬400dp的屏幕,她左邊對其50%的位置,對于寬600dp的屏幕,她左邊對其67%的位置。當必須要使用大數值的dp時,如輪播圖的高度等,可以對數值坐下屏幕適配。 寫在最后的話
屏幕適配是個很繁雜的問題,可是一般也不用太受它困擾,我們只要使用dp去編寫界面,就能滿足大部分的適配要求,然后在針對測試出來的適配問題去專門適配就好。
參考
Android 屏幕適配方案 Android開發:最全面、最易懂的Android屏幕適配解決方案 官方文檔