一、基礎知識
1.Android中常用的距離單位
-
px(像素):每個px對應屏幕上的一個點。
-
dip或dp:(device independent pixels,設備獨立像素):一種基於屏幕密度的抽象單位。在每英寸160點的顯示器上,1dip=1px.單隨着屏幕的密度改變,dip和px的換算也會發生改變
-
sp(scaled pixels, 比例像素):主要處理字體的大小,可以根據用戶的字體大小首選項進行縮放。
-
in(英寸):標準長度單位,1 英寸=2.54 釐米。
-
mm(毫米):標準長度單位。
-
pt(磅):標準的長度單位, 1/72英寸。
2.重要概念
2.1 屏幕尺寸
- 含義:手機對角線的物理尺寸
- 單位:英寸(inch),1英寸=2.54cm
2.2 屏幕分辨率
- 含義:手機在橫向、縱向上的像素點數總和
- 例子:1920x1080,即高度方向上有1920個像素點,寬度方向上有1080個像素點
- 單位:px(pixel),1px=1像素點
- Android手機常見的分辨率:320x480、480x800、720x1280、1080x1920
2.3 屏幕像素密度
- 含義:每英寸的像素點數
- 單位:dpi(dots per ich)
- 安卓手機對於每類手機屏幕大小都有一個相應的屏幕像素密度:
密度類型 | 代表的分辨率(px) | 屏幕像素密度(dpi) | 換算(px/dp) |
---|---|---|---|
低密度(ldpi) | 240x320 | 120 | 1dp=0.75px |
中密度(mdpi) | 320x480 | 160 | 1dp=1px |
高密度(hdpi) | 480x800 | 240 | 1dp=1.5px |
超高密度(xhdpi) | 720x1280 | 320 | 1dp=2px |
超超高密度(xxhdpi) | 1080x1920 | 480 | 1dp=3px |
2.4 屏幕尺寸、分辨率、像素密度三者關係
二、目前流行的屏幕適配方案
1.今日頭條適配方案
-
官方文章:一種極低成本的Android屏幕適配方式
-
講解比較好的博客:騷年你的屏幕適配方式該升級了!-今日頭條適配方案
-
對方案的優化封裝:今日頭條屏幕適配方案終極版正式發佈
使用的原生api介紹:
android中的dp在渲染前會將dp轉爲px,計算公式:
px = density * dp;
density = dpi / 160;
px = dp * (dpi / 160);
density 是 DisplayMetrics 中的成員變量
DisplayMetrics#density 就是上述的density
DisplayMetrics#densityDpi 就是上述的dpi
DisplayMetrics#scaledDensity 字體的縮放因子,正常情況下和density相等,但是調節系統字體大小後會改變這個值
對dp的總結:
- 兩個屏幕物理寬度相等,則兩個屏幕的總寬度dp也相等
- dp作用是保持相同dp的大小在不同分辨率不同像素密度的屏幕上展示的實際大小一致,但是就造成了大小跟屏幕比例的不同
- dp等於物理定長:因爲160像素密度下1dp=1px,而像素密度是1英寸包含的像素數,因此160像素密度下
1英寸=160px=160dp
,所以1dp=(1/160*)(inch)=(2.54/160)(cm)
今日頭條方案總結:
- 修改density 保持屏幕總寬度dp不變,將density的計算方法 從根據像素密度/160 改成了 屏幕像素寬度/屏幕的目標寬度dp。原來的density的作用是換算出不同情況下dp對應的px,達到如上面描述dp的效果,而方案修改後的density的作用是實現相同的dp大小的view在屏幕中所佔比例相同。也就導致了屏幕總寬度dp變大沒有展示更多的內容,而是放大了view,跟原來展示內容一樣多。
- 也可以理解爲:根據ui設計圖的寬度dp值,算出當前屏幕每dp佔當前屏幕多少像素值(也就是所說的density)
2.smallestWidth限定符適配方案
- 方案介紹:Android 目前最穩定和高效的UI適配方案
- 講解比較好的博客:騷年你的屏幕適配方式該升級了!-SmallestWidth 限定符適配方案
總結:
- 其實 smallestWidth 限定符屏幕適配方案 的原理和 今日頭條屏幕適配方案 挺像的,今日頭條屏幕適配方案 是根據屏幕的寬度或高度動態調整每個設備的 density (每 dp 佔當前設備屏幕多少像素),而 smallestWidth 限定符屏幕適配方案 同樣是根據屏幕的寬度動態調整每個設備 每份佔的 dp 值
- 也可以理解爲:根據ui設計圖的寬度dp值,算出當前屏幕分成ui設計圖的寬度dp份後,每dp佔當前屏幕實際多少dp,然後這個實際dp值再根據dpi轉換成具體像素值
3.使用pt作長度單位的適配方案
- 方案介紹:Android 屏幕適配終結者
首先科普下 Android 中的一個長度單位:pt,它表示一個點,是屏幕的物理尺寸,其大小爲 1 英寸的 1 / 72,也就是 72pt 等於 1 英寸(其實 Android 中還有比較少見的 in 和 mm 的長度單位)。
原理其實也是基於頭條的原理,不過是操作 pt,所以不是改 DisplayMetrics#density,而是 DisplayMetrics#xdpi,系統不同單位換算爲px代碼如下:
public static float applyDimension(int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
至於爲什麼不使用in或者mm,作者回答是“尺寸太大了,pt 比較適中”。
三、總結
三種方案各自的優缺點:方案比較
目前推薦使用第一、三種方案,因爲第二個smallestWidth限定符適配方案侵入性太高,如果項目想切換爲其他屏幕適配方案,因爲每個 Layout 文件中都存在有大量 dimens 的引用,這時修改起來工作量非常巨大,切換成本非常高昂。