[Android] Android開發中dip,dpi,density,px等詳解

Android開發中的各種單位的解釋


  • Px (Pixel像素)
    也稱為圖像元素,是作為圖像構成的基本單元,單個像素的大小并不固定,跟隨屏幕大小和像素數量的關系變化(屏幕越大,像素越低,單個像素越大,反之亦然)。所以在使用像素作為設計單位時,在不同的設備上可能會有縮放或拉伸的情況。

  • Resolution(分辨率)
    是指屏幕的垂直和水平方向的像素數量,如果分辨率是 1920*1080 ,那就是垂直方向有 1920 個像素,水平方向有 1080 個像素。

  • Dpi(像素密度)
    是指屏幕上每英寸(1英寸 = 2.54 厘米)距離中有多少個像素點。如果屏幕為 320*240,屏幕長 2 英寸寬 1.5 英寸,Dpi = 320 / 2 = 240 / 1.5 = 160。

  • Density(密度)
    這個是指屏幕上每平方英寸(2.54 ^ 2 平方厘米)中含有的像素點數量。

  • Dip / dp (設備獨立像素)
    也可以叫做dp,長度單位,同一個單位在不同的設備上有不同的顯示效果,具體效果根據設備的密度有關,詳細的公式請看下面 。

計算規則


我們以一個 4.95 英寸 1920 * 1080 的 nexus5 手機設備為例:

Dpi :

  1. 計算直角邊像素數量: 19202+10802=2202^2(勾股定理)。
  2. 計算 DPI:2202 / 4.95 = 445。
  3. 得到這個設備的 DPI 為 445 (每英寸的距離中有 445 個像素)。

Density

上面得到每英寸中有 440 像素,那么 density 為每平方英寸中的像素數量,應該為: 445^2=198025。

Dip

  1. 先明白一個概念,所有顯示到屏幕上的圖像都是以 px 為單位。
  2. Dip 是我們開發中使用的長度單位,最后他也需要轉換成 px。
  3. 計算這個設備上 1dip 等于多少 px:
    px = dip x dpi /160
    px = 1 x 445 / 160 = 2.78
  4. 通過上面的計算可以看出在此設備上 1dip = 2.78px,那么這是一個真實的故事嗎? nonono,其中的關鍵值 dpi 并不是我們算出來的 445 ,請往下看。

Android 系統定義的 Dpi


上面計算的 445Dpi 是在 4.95 英寸下的 1920*1080 手機,那如果是 4.75 分辨率下的呢? 4.55 分辨率下的呢?。。。??梢娛呛苈闊┑模粋€分辨率在不同的屏幕尺寸上 Dpi 也不相同。為了解決這個問題, Android 中內置了幾個默認的 Dpi ,在特定的分辨率下自動調用,也可以手動在配置文件中修改。

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

這是內置的 Dpi ,啥意思? 在 1920*1080 分辨率的手機上 默認就使用 480 的 dpi ,不管的你的尺寸是多大都是這樣,除非廠家手動修改了配置文件,這個我們后面再說。
我們親自嘗試一下:

<TextView    
  android:id="@+id/tv"   
  android:layout_width="200dp"    
  android:layout_height="100dp"    
  android:text="Hello World!" />

這是一個 textview,高為 200dp 寬為 100dp 。按照我們之前的公式手動計算:

height = 100 x 445 / 160 = 278.5px
width  = 200 x 445 / 160 = 556.25px

我們用下列代碼獲取到控件的實際像素看看是否相同:

layout = (RelativeLayout)findViewById(R.id.la);
//要在控件繪制完成后才能獲取到相關信息,所以這里要監聽繪制狀態
layout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()     {    
  public boolean onPreDraw() {        
    Log.d("hehehe", textView.getHeight() + "/" + textView.getWidth());       
    return true;    
  }
});

輸出的結果為:300/600
內部計算過程為:

height = 100 x 480 / 160 = 300px
width  = 200 x 480 / 160 = 600px

其中的 160 是基準值不會變的, 100 和200 是我們設置的 dp ,那么這 480 是從何而來的?說好的 445 呢?
找到我們手機中的 /system/build.prop 文件,其中有一行是這樣:
ro.sf.lcd_density=480

這就指定了這個機型使用的dpi是多少,還有一種情況是沒有這一行(我在模擬器中發現過),那么應該是根據表格中的分辨率來自動設置。

我更改這行為:
ro.sf.lcd_density=320

再次運行上面的測試代碼,輸出結果為:200/400
內部計算過程為:

height = 100 x 320 / 160 = 200px
width  = 200 x 320 / 160 = 400px

說到底,因為有dpi這個動態的系數,我們在使用dp的時候才能兼容不同分辨率的設備。

到這里,應該都明白了 dpi 的由來,以及系統 dpi 跟物理 dpi 并不一定相同。在系統中使用的全部都是系統 dpi,沒有使用物理 dpi,也獲取不到物理 dpi。物理 dpi 主要用于廠家對于手機的參數描述(也可以看做 ppi )!

然后。。表格中還有一個東西叫做基準比例,這個其實就是計算 dp -> px 中重要的系數,以 160 為基準,其他的除以 160 得到比例,我們這樣看:

height = 100 x 480 / 160 = 300px
width  = 200 x 480 / 160 = 600px

其中的480/160其實就是在求基準比例,這里得到3。如果在熟悉上表的情況下看到機型的分辨率,在設置dp的時候可以直接心算出相對應的px,心算過程如下:

分辨率:1080x1920 -> 系統 DPI:480 -> 基準比例:480 / 160 = 3 -> 對應px:100 x 3 = 300
分辨率:720x1280 -> 系統 DPI:320 -> 基準比例:320 / 160 = 2 -> 對應px:100 x 2 = 200
分辨率:480x800 -> 系統 DPI:240 -> 基準比例:240 / 160 = 1.5 -> 對應px:100 x 1.5 = 150
分辨率:320x480 -> 系統 DPI:160 -> 基準比例:160 / 160 = 1 -> 對應px:100 x 1 = 100
分辨率:240x320 -> 系統 DPI:120 -> 基準比例:120 / 160 = 0.75 -> 對應px:100 x 0.75 = 75
...................

總結:

1. dpi(每英寸像素數)是有預設值的!120-160-240-320-480。對應不同的分辨率。

2. 基準比例 = dpi(每英寸像素數) / 160

3. px = dp x 基準比例

從代碼中獲取相關數值


我們主要使用的類是:DisplayMetrics

以下為官方api說明
A structure describing general information about a display, such as its size, density, and font scaling.
To access the DisplayMetrics members, initialize an object like this:

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

這是一個獲取屏幕信息的類,比如大小,密度等。以及初始化的方法。

實際運用如下:

DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
//通常我們在使用DisplayMetrics時,都是直接獲取內部變量來使用。所以下面直接列出各個內部變量。

dm.ydpi;     //得到物理屏幕上 Y 軸方向每英寸的像素
dm.xdpi;     //得到物理屏幕上 X 軸方向每英寸的像素 
             //ps:  其實這兩個大多數情況下都是相同的
             //你能想象上面像素密度大很清晰 下面密度小跟馬賽克一樣嗎 233333

dm.density;           //獲取當前設備的基準比例
dm.densityDpi;        //獲取系統dpi,隨著 build.prop 文件中的代碼而改變。

dm.widthPixels;       //獲取屏幕寬度的像素數量

//獲取屏幕高度的像素數量!
//注意 - 因為這里會自動減去32dp的像素數量,根據分辨率不同的設備,減去的像素數量也不同,但是可以根據公式推算完整(px = dp x 基準比例)。
/*為啥不用dm.densityDpi / 160 得到基準比例?
  因為那個會隨著build.prop文件代碼變更而更改,算出來的不一定準確*/
dm.heightPixels + 32 * dm.ydpi / 160;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容