Android 徹底搞清“dp(dip)”

前言:大家都知道"dp"這個單位,在Android上畫布局時使用,用來取代px,使得畫出的控件能夠在不同手機上展示出相圖的效果。記得有人這樣跟我描述過:某個dp長度的一條線,在一個手機上展示是1cm,在其他手機上都會展示爲1cm。dp是如何工作讓不同屏幕手機展示“相同效果”呢?上面對dp展示的描述是否準確呢?

答案是並不是這樣。

以下內容有幾個簡單的計算公式(小學數學水平)需要注意,還要注意dpi和dip的區別。


參考資料

https://www.jianshu.com/p/5678f23faed3

強烈建議看這篇文章: https://www.jianshu.com/p/cd66b7e01d4a

https://www.cnblogs.com/H-BolinBlog/p/5647548.html

今日頭條屏幕適配方案

百度百科


1.屏幕基礎概念

像素(px):是指在由一個數字序列表示的圖像中的一個最小單位,稱爲像素。

分辨率(Resolution):這裏指物理分辨率,是液晶屏最高可顯示的像素數(假設一個發光點能顯示一個像素點,可以簡單理解爲屏幕設備能發光的點數)。

dpi(Dots Per Inch,每英寸點數):每英寸的像素點數。

density:每平方英寸像素點數。

我有下面這樣一部手機,藍色的是發光點。那麼這部手機屏幕的dpi是3,density就是3的平方9。這部手機的分辨率是20(5乘以4),最高能顯示分辨率爲20的圖片。

從上面概念看,dpi是每英寸的像素點數,density是每平方英寸像素點數,大多數手機x軸方向的dpi和y軸方向dpi是相同的,從概念上可以得出density和dpi是平方的關係:density= dpi^{2}

再來看dpi和分辨率的關係,如果手機屏幕面積爲s,則density = Resolution / s,dpi = \sqrt{density} = \sqrt{Resolution / s}

dip(Device Independent Pixels,設備獨立像素):基於計算機控制的座標系統和抽象像素(虛擬像素),由底層系統的程序使用,轉換爲物理像素的應用。

概念有點複雜,簡單理解就是:我代碼設置了1dip寬度的一個按鈕,用不同的手機顯示,我用尺子量都是一樣長度(就是一樣的物理長度)。

怎麼達到這樣的效果呢?

需要dpi和px一起來合作計算。我們知道了:dpi是每英寸像素點數,px是像素點數,那我有60px的實際物理長度不就是(60/dpi)英寸嘛,1px的實際長度就是 1/dpi 英寸咯可以得到公式:長度 L(英寸) = px /  dpi。手機的dpi不同,那1px的物理長度其實就不同。

 dip其實爲了達到展示一樣物理長度才弄出來的一個概念,最後還是需要轉換成像素來顯示的。

爲了讓每部手機上dip都顯示一樣物理長度,那隻需要dip和px轉換滿足關係:dip = n * px /dpi (n > 0)。那麼

px = dip * dpi / n。設備通過這樣的對應關係來決定顯示的像素值,這樣顯示出的像素值不同,而保證物理長度相同了。

我們來算一下看。比如20dip的長度:先計算20dip對應的px爲20 * dpi /n,物理長度爲 px / dpi = (20 * dpi / n) /dpi = 20/n(英寸)。n是一個固定值,那麼對於所有設備來說, 20 dip都會顯示成 20/n 英寸長的像素。

 

Android將這個n值定爲160。這個值設爲160,是因爲第一款Android設備(HTC的T-Mobile G1)是屬於160dpi。

那麼,當設備dpi爲160時,1px = 1dip。

2.dip的值

通過上面的計算過程,可以讓dip使用者達到不同手機顯示相同效果。dip轉換成實際顯示要用的px,需要用到dpi。根據公式dpi = \sqrt{density} = \sqrt{Resolution / s},可以看出,每個設備的dip與設備的分辨率和麪積相關。

實際,Android在進行換算時做了個偷懶,並沒有根據設備的分辨率和麪積來計算。而是內置了幾個默認的 dpi ,在特定的分辨率下自動調用,忽略考慮設備的面積(廠商也可以根據自己設備修改系統參數,來自定義dpi)。

         分辨率        dpi    基準比例
ldpi     240x320      120     0.75
mdpi     320x480      160     1
hdpi     480x800      240     1.5
xhdpi    720x1280     320     2
xxhdpi   1080x1920    480     3

手機中的 /system/build.prop 文件中有一行定義了系統使用的dpi(有些廠商會自行修改):

ro.sf.lcd_density=480

可以看出系統中提供的dpi和設備屏幕的物理dpi在android默認情況下不相同。

可以通過以上代碼獲取系統提供的屏幕信息:

 DisplayMetrics metrics = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(metrics);

介紹DisplayMetrics中的一些成員變量:

// 設備的基準比例,density = dpi / 160 
// (這裏的density僅代表基準比例,與我們上面基礎概念中的density並不相同,注意不要混淆)
// px = density * dip
density

// 系統提供的dpi
// density = densityDpi / 160
// px = densityDpi * dip /160
densityDpi

如此,可以得出結論,Android中dip可以根據屏幕就分辨率動態適配爲合適的px。由於沒有考慮屏幕尺寸,使得相同dip在不同手機上並不能達到完全相同的物理效果。如果廠商根據自己設備設置合理的dpi,是可以達到相同的效果的。


3.Android系統自帶dp轉px的方法

    public static float dp2px(float dp) {
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章