Android開發(fā)中的各種單位的解釋
Px (Pixel像素)
也稱為圖像元素筝家,是作為圖像構(gòu)成的基本單元洼裤,單個像素的大小并不固定,跟隨屏幕大小和像素數(shù)量的關(guān)系變化(屏幕越大溪王,像素越低腮鞍,單個像素越大,反之亦然)莹菱。所以在使用像素作為設(shè)計單位時移国,在不同的設(shè)備上可能會有縮放或拉伸的情況。Resolution(分辨率)
是指屏幕的垂直和水平方向的像素數(shù)量道伟,如果分辨率是 1920*1080 迹缀,那就是垂直方向有 1920 個像素使碾,水平方向有 1080 個像素。Dpi(像素密度)
是指屏幕上每英寸(1英寸 = 2.54 厘米)距離中有多少個像素點(diǎn)祝懂。如果屏幕為 320*240票摇,屏幕長 2 英寸寬 1.5 英寸,Dpi = 320 / 2 = 240 / 1.5 = 160砚蓬。Density(密度)
這個是指屏幕上每平方英寸(2.54 ^ 2 平方厘米)中含有的像素點(diǎn)數(shù)量矢门。Dip / dp (設(shè)備獨(dú)立像素)
也可以叫做dp,長度單位灰蛙,同一個單位在不同的設(shè)備上有不同的顯示效果颅和,具體效果根據(jù)設(shè)備的密度有關(guān),詳細(xì)的公式請看下面 缕允。
計算規(guī)則
我們以一個 4.95 英寸 1920 * 1080 的 nexus5 手機(jī)設(shè)備為例:
Dpi :
- 計算直角邊像素數(shù)量: 19202+10802=2202^2(勾股定理)峡扩。
- 計算 DPI:2202 / 4.95 = 445。
- 得到這個設(shè)備的 DPI 為 445 (每英寸的距離中有 445 個像素)障本。
Density
上面得到每英寸中有 440 像素教届,那么 density 為每平方英寸中的像素數(shù)量,應(yīng)該為: 445^2=198025驾霜。
Dip
- 先明白一個概念案训,所有顯示到屏幕上的圖像都是以 px 為單位。
- Dip 是我們開發(fā)中使用的長度單位粪糙,最后他也需要轉(zhuǎn)換成 px强霎。
- 計算這個設(shè)備上 1dip 等于多少 px:
px = dip x dpi /160
px = 1 x 445 / 160 = 2.78 - 通過上面的計算可以看出在此設(shè)備上 1dip = 2.78px,那么這是一個真實的故事嗎蓉冈? nonono城舞,其中的關(guān)鍵值 dpi 并不是我們算出來的 445 ,請往下看寞酿。
Android 系統(tǒng)定義的 Dpi
上面計算的 445Dpi 是在 4.95 英寸下的 1920*1080 手機(jī)家夺,那如果是 4.75 分辨率下的呢? 4.55 分辨率下的呢伐弹?拉馋。。惨好。煌茴。可見是很麻煩的日川,同一個分辨率在不同的屏幕尺寸上 Dpi 也不相同蔓腐。為了解決這個問題, Android 中內(nèi)置了幾個默認(rèn)的 Dpi 逗鸣,在特定的分辨率下自動調(diào)用合住,也可以手動在配置文件中修改绰精。
ldpi | mdpi | hdpi | xhdpi | xxhdpi | |
---|---|---|---|---|---|
分辨率 | 240x320 | 320x480 | 480x800 | 720x1280 | 1080x1920 |
系統(tǒng)dpi | 120 | 160 | 240 | 320 | 480 |
基準(zhǔn)比例 | 0.75 | 1 | 1.5 | 2 | 3 |
這是內(nèi)置的 Dpi 撒璧,啥意思透葛? 在 1920*1080 分辨率的手機(jī)上 默認(rèn)就使用 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);
//要在控件繪制完成后才能獲取到相關(guān)信息,所以這里要監(jiān)聽繪制狀態(tài)
layout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
Log.d("hehehe", textView.getHeight() + "/" + textView.getWidth());
return true;
}
});
輸出的結(jié)果為:300/600
內(nèi)部計算過程為:
height = 100 x 480 / 160 = 300px
width = 200 x 480 / 160 = 600px
其中的 160 是基準(zhǔn)值不會變的蹄胰, 100 和200 是我們設(shè)置的 dp 岳遥,那么這 480 是從何而來的?說好的 445 呢裕寨?
找到我們手機(jī)中的 /system/build.prop 文件浩蓉,其中有一行是這樣:
ro.sf.lcd_density=480
這就指定了這個機(jī)型使用的dpi是多少,還有一種情況是沒有這一行(我在模擬器中發(fā)現(xiàn)過)宾袜,那么應(yīng)該是根據(jù)表格中的分辨率來自動設(shè)置捻艳。
我更改這行為:
ro.sf.lcd_density=320
再次運(yùn)行上面的測試代碼,輸出結(jié)果為:200/400
內(nèi)部計算過程為:
height = 100 x 320 / 160 = 200px
width = 200 x 320 / 160 = 400px
說到底庆猫,因為有dpi這個動態(tài)的系數(shù)认轨,我們在使用dp的時候才能兼容不同分辨率的設(shè)備。
到這里月培,應(yīng)該都明白了 dpi 的由來嘁字,以及系統(tǒng) dpi 跟物理 dpi 并不一定相同。在系統(tǒng)中使用的全部都是系統(tǒng) dpi杉畜,沒有使用物理 dpi拳锚,也獲取不到物理 dpi。物理 dpi 主要用于廠家對于手機(jī)的參數(shù)描述(也可以看做 ppi )寻行!
然后霍掺。。表格中還有一個東西叫做基準(zhǔn)比例拌蜘,這個其實就是計算 dp -> px 中重要的系數(shù)杆烁,以 160 為基準(zhǔn),其他的除以 160 得到比例简卧,我們這樣看:
height = 100 x 480 / 160 = 300px
width = 200 x 480 / 160 = 600px
其中的480/160其實就是在求基準(zhǔn)比例兔魂,這里得到3。如果在熟悉上表的情況下看到機(jī)型的分辨率举娩,在設(shè)置dp的時候可以直接心算出相對應(yīng)的px析校,心算過程如下:
分辨率:1080x1920 -> 系統(tǒng) DPI:480 -> 基準(zhǔn)比例:480 / 160 = 3 -> 對應(yīng)px:100 x 3 = 300
分辨率:720x1280 -> 系統(tǒng) DPI:320 -> 基準(zhǔn)比例:320 / 160 = 2 -> 對應(yīng)px:100 x 2 = 200
分辨率:480x800 -> 系統(tǒng) DPI:240 -> 基準(zhǔn)比例:240 / 160 = 1.5 -> 對應(yīng)px:100 x 1.5 = 150
分辨率:320x480 -> 系統(tǒng) DPI:160 -> 基準(zhǔn)比例:160 / 160 = 1 -> 對應(yīng)px:100 x 1 = 100
分辨率:240x320 -> 系統(tǒng) DPI:120 -> 基準(zhǔn)比例:120 / 160 = 0.75 -> 對應(yīng)px:100 x 0.75 = 75
...................
總結(jié):
1. dpi(每英寸像素數(shù))是有預(yù)設(shè)值的构罗!120-160-240-320-480。對應(yīng)不同的分辨率智玻。
2. 基準(zhǔn)比例 = dpi(每英寸像素數(shù)) / 160
3. px = dp x 基準(zhǔn)比例
從代碼中獲取相關(guān)數(shù)值
我們主要使用的類是: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);
這是一個獲取屏幕信息的類遂唧,比如大小,密度等吊奢。以及初始化的方法盖彭。
實際運(yùn)用如下:
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
//通常我們在使用DisplayMetrics時,都是直接獲取內(nèi)部變量來使用页滚。所以下面直接列出各個內(nèi)部變量召边。
dm.ydpi; //得到物理屏幕上 Y 軸方向每英寸的像素
dm.xdpi; //得到物理屏幕上 X 軸方向每英寸的像素
//ps: 其實這兩個大多數(shù)情況下都是相同的
//你能想象上面像素密度大很清晰 下面密度小跟馬賽克一樣嗎 233333
dm.density; //獲取當(dāng)前設(shè)備的基準(zhǔn)比例
dm.densityDpi; //獲取系統(tǒng)dpi,隨著 build.prop 文件中的代碼而改變裹驰。
dm.widthPixels; //獲取屏幕寬度的像素數(shù)量
//獲取屏幕高度的像素數(shù)量隧熙!
//注意 - 因為這里會自動減去32dp的像素數(shù)量,根據(jù)分辨率不同的設(shè)備幻林,減去的像素數(shù)量也不同贞盯,但是可以根據(jù)公式推算完整(px = dp x 基準(zhǔn)比例)。
/*為啥不用dm.densityDpi / 160 得到基準(zhǔn)比例滋将?
因為那個會隨著build.prop文件代碼變更而更改邻悬,算出來的不一定準(zhǔn)確*/
dm.heightPixels + 32 * dm.ydpi / 160;