文章來自:
PX(pixel 像素)
px 也叫像素點(diǎn),是屏幕物理上的最小顯示單位,如手機(jī)分辨率 1080 x 1920 表示寬有 1080 像素點(diǎn),高有 1920 像素點(diǎn)。像素的大小是沒有固定長(zhǎng)度的,不同設(shè)備上一個(gè)單位像素色塊的大小是不一樣的。尺寸面積大小相同的兩塊屏幕,分辨率大小可以是不一樣的,分辨率高的屏幕上面像素點(diǎn)(色塊)就多,所以屏幕內(nèi)可以展示的畫面就更細(xì)致,單個(gè)色塊面積更小,而分辨率低的屏幕上像素點(diǎn)(色塊)更少,單個(gè)像素面積更大,可以顯示的畫面就沒那么細(xì)致。
dpi(dots per inch)
dpi也被稱為屏幕密度,就是每英寸所打印的點(diǎn)數(shù)。實(shí)際上dpi的計(jì)算是通過勾股定理算出屏幕對(duì)角的像素?cái)?shù)再除以對(duì)角的尺寸就是最終的dpi。以一臺(tái)的機(jī)器為例:
- 尺寸:6.0英寸(一般所說的尺寸就是機(jī)器的對(duì)角線尺寸。)
- 分辨率:1080*1920
那么dpi算法則為1080的平方加上2160的平方再開方約等于2203。再用2203除以6得到約367。則367dpi為該機(jī)器的像素密度。
ppi(pixels per inch)
ppi和dpi這兩個(gè)措辭的差別,表面上看來只在于是在談 dot,還是 pixel,但實(shí)際上 dot 可以打印的墨點(diǎn),可以指掃描儀的采樣點(diǎn),可以指數(shù)字圖像的最小單位(即 pixel),可以指屏幕的物理像素,可以指操作系統(tǒng)的抽象像素……在不同的語境下可以指不同的概念,而同樣 pixel 也可以指數(shù)字圖像的數(shù)據(jù) pixel,可以指屏幕物理像素,也可以指代操作系統(tǒng)的抽象像素……在不同語境下的意義也不同。這兩個(gè)單位完全就是時(shí)?;煊玫?,在電子屏幕顯示中提到的 ppi 和 dpi 可以認(rèn)為是一樣的,所以你可以忽略在措辭上用 dpi 或者 ppi 有什么不同,不過在 Android 平臺(tái)上常用 dpi 這種表述方式。
dp/dip(device independent pixels)
dp也稱設(shè)備獨(dú)立像素,dp和dip是同一個(gè)概念,都是device independent pixels的簡(jiǎn)稱。舉個(gè)例子:
寬2英寸,長(zhǎng)3英寸的屏幕上,如果將一個(gè)控件的寬度設(shè)為160px,則會(huì)出現(xiàn)如下的情況:
- 屏幕分辨率寬度為320px,則該控件占據(jù)屏幕寬度一半。
- 屏幕分辨率寬度為640px,則該控件占據(jù)屏幕寬度的四分之一。
這十分影響體驗(yàn)。所以Android引入了設(shè)備獨(dú)立像素的概念,也就是dp這種單位。首先Android規(guī)定在160dpi的設(shè)備上1dp=1px,當(dāng)屏幕密度為320dpi時(shí),1dp=2px,以此類推。。。正式如此,我們得以保證控件在不同屏幕密度上顯示一致,從而完成屏幕適配?;氐缴厦娴睦樱?dāng)我們使用新的單位dp時(shí),當(dāng)將控件的寬度設(shè)為160dp: - 在分辨率為 320 x 480(既 dpi 為 160)的屏幕上,則 160dp 等價(jià)于 160px,控件占屏幕寬的一半;
在分辨率為 640 x 960(既 dpi 為 320)的屏幕上,則 160dp 等價(jià)于 320px,控件依然占屏幕寬的一半,就解決大小比例不一致的問題。
下面是網(wǎng)上常用的 dp 和 px 之間轉(zhuǎn)換的工具類:
public static int dp2px(Context context, int values) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (values * scale + 0.5f);
}
public static int px2dip(Context context, float pxValue) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
//+0.5 就是為了在精度丟失的情況下進(jìn)行四舍五入。
drawable 目錄加載和 dpi 間的關(guān)系
說到 dpi 這里就不得不聯(lián)想到在 Android 工程里 res 目錄下的 drawable-hdpi, drawable-xhdpi, drawable-xxhdpi 等文件夾。我們知道 Android 會(huì)根據(jù)屏幕的 dpi 去選擇對(duì)應(yīng)的 drawable 文件夾,Android項(xiàng)目的資源文件下存在以下目錄:
- drawable-ldpi ( 當(dāng)dpi為120時(shí),使用此目錄下的資源)
- drawable-mdpi ( 當(dāng)dpi為160時(shí),使用此目錄下的資源)
- drawable-hdpi ( 當(dāng)dpi為240時(shí),使用此目錄下的資源)
- drawable-xhdpi ( 當(dāng)dpi為320時(shí),使用此目錄下的資源)
- drawable-xxhdpi ( 當(dāng)dpi為480時(shí),使用此目錄下的資源)
- drawable-xxxhdpi ( 當(dāng)dpi為640時(shí),使用此目錄下的資源)
Android 正是根據(jù)設(shè)備DPI值得不同,選擇清晰度不同的資源使用,完成屏幕的適配, 可以看出系數(shù)比例關(guān)系:0.75:1:1.5:2:3:4,但手機(jī)屏幕千奇百怪,例如如果一個(gè)手機(jī)屏幕是 420 dpi 不屬于上述文件分類中的任何一個(gè),因此上述文件夾不是指定具體的分辨率,而是一個(gè)范圍:
- drawable-ldpi(value <= 120 dpi)
- drawable-mdpi(120 dpi < value <= 160 dpi)
- drawable-hdpi(160 dpi < value <= 240 dpi)
- drawable-xhdpi(240 dpi < value <= 320 dpi)
- drawable-xxhdpi(320 dpi < value <= 480 dpi)
- drawable-xxxhdpi(480 dpi < value <= 640 dpi)
以此類推,所以 420 dpi 會(huì)優(yōu)先加載 xxdpi 中的資源文件,如果對(duì)應(yīng) dpi 目錄下沒有找到該資源文件,遵循先高再低原則,然后按比例縮放圖片,比如當(dāng)前為 xhdpi 設(shè)備,則 drawable 的尋找順序?yàn)椋?br> xhdpi -> xxhdpi -> xxxhdpi (如果沒有更高的了) -> nodpi (如果有的話) -> hdpi -> mdpi,如果在 xxhdpi 中找到目標(biāo)圖片,則壓縮 2/3 來使用,如果在 mdpi 中找到圖片,則放大 2 倍來使用。
sp(scalable pixels)
最后來說一說 sp,sp 與縮放無關(guān)的像素單位,類似 dp ,不同之處在于它還會(huì)根據(jù)用戶字體大小配置而縮放。所以開發(fā)中指定字體大小時(shí)建議使用 sp ,因?yàn)?sp 作為字體大小單位會(huì)隨著系統(tǒng)的字體大小改變,下面是 sp 和 px 之間轉(zhuǎn)換工具類:
public static int px2sp(Context context, float pxValue) {
float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
從代碼中也可以看出 sp 和 px 間轉(zhuǎn)換使用的是 scaledDensity,而 dp 和 px 間轉(zhuǎn)換使用的是 density,也就是 sp 會(huì)隨著系統(tǒng)字體設(shè)置縮放,dp 不會(huì)。
一般UI拿過來的圖就是px標(biāo)注的,然后會(huì)告訴你做圖時(shí)所用的尺寸是多大的,如1334x750,4.7寸的屏幕
- 計(jì)算UI給出的圖紙屏幕的dpi:
1334*1344+750*750=2342056
2342056開方約等于1530
1530/4.7=325dpi
- 所以在325dpi下為80px,在標(biāo)準(zhǔn)的160dpi的計(jì)算為:
80 * 160 / 325 約等于40px。
在160dpi的像素為40px,所以設(shè)置為40dp。