Android開發:android中的dp,px深入解析 -

來源:互聯網
上載者:User

dip: device independent pixels(裝置獨立像素)。不同裝置有不同的顯示效果,這個和裝置硬體有關,一般我們為了支援WVGA、HVGA和QVGA 推薦使用這個,不依賴像素。

  與密度無關的像素,這是一個基於螢幕物理密度的抽象單位。密度可以理解為每英寸包含的像素個數(單位是dpi),1dp實際上相當於密度為160dpi的屏上的一個點(可否理解為物理尺寸?)。也就是說,如果螢幕物理密度是160dpi時,dp和px是等效的。現在用實際的手機螢幕說一下。一塊擁有320*480解析度的手機螢幕,如果寬度是2英寸,高度是3英寸,這塊螢幕的密度就是160dpi。如果螢幕大小未變,而解析度發生了變化,例如,解析度由320*480變成了480*800,這時螢幕的物理密度就變大了(大於160dpi)。這就意味著螢幕每英寸可以顯示更多的像素點,螢幕的顯示效果就更細膩了。假設一個撳鈕的寬度使用dp作為單位,在160dpi時設為160,而在更高的dpi下(如320dpi),按鈕的寬度看上去和160dpi時的螢幕一樣。這是由於系統在發現螢幕的密度不是160dpi時,會計算一個轉換比例,然後用這個比例與實際尺寸相乘就得出新的尺寸。計算比例的方法是目標螢幕的密度除以160.如果目標螢幕的密度是320dpi,那麼這個比例就是2。如果按鈕的寬度是160dp,那麼在320dpi的螢幕上的寬度就是320個像素點(dp是抽象單位,在實際的螢幕上應轉換成像素點)。從這一點可以看出,dp可以自適應螢幕的密度。不管螢幕密度怎樣變化,只要螢幕的物理尺寸不變,實際顯示的尺寸就不會變化。如果將按鈕的寬度設成160px,那麼在320dpi的螢幕上仍然會是160個像素點,看上去按鈕的寬度只是160dpi螢幕的一半。Android官方建議棄置表示寬度,高度,位置等屬性時應盡量使用dp作為尺寸單位。
  據px = dip * density / 160,則當螢幕密度為160時,px = dip。根據 google 的建議,TextView 的字型大小最好使用 sp 做單位,而且查看TextView的源碼可知Android預設使用sp作為字型大小單位。將dip作為其他元素的單位。
  備忘: 根據google的推薦,像素統一使用dip,字型統一使用sp
  舉個例子區別px和dip:
  px就是像素,如果用px,就會用實際像素畫,比個如吧,用畫一條長度為240px的橫線,在480寬的模擬器上看就是一半的屏寬,而在320寬的模擬器上看就是2/3的屏寬了。
而dip,比如你做一條160dip的橫線,無論你在320還480的模擬器上,都是一半屏的長度(當螢幕尺寸不變時)。

public static int dip2px(Context context, float dipValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}public static int px2dip(Context context, float pxValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}

下面這篇文章可以做深入理解之參考,[url=http://blog.csdn.net/eggcalm/article/details/7006378]查看原文[/url]:
今天偶然間問了同事一個關於dp單位的問題,然後由這個問題引發的一連串的問題徹底顛覆了我關於dp的理論體系。

我那個問題是這樣的:既然dp的本質是物理尺寸,為什麼不用cm或者mm等傳統長度單位替代?

然後他回答我dp是和像素密度無關的。。。我對這個回答不屑一顧,不過他接下來的一句話把我徹底震驚了,那句話是這樣的:在你的手機上320dp就剛好滿屏了,310dp就差一點點滿屏。

My Phone是HTC Desire,這個理論我聞所未聞,然後馬上做了個小實驗,事實確實是這樣,把一個TextView背景設成紅色,寬度設成320dp,能看到滿屏,310dp就差那麼一點點。

看到這個測試結果的時候,我再一次崩潰了,我希望同事第二句話是一個美麗的錯誤,我無法接受這麼久以來我理解的東西是錯誤的,可是事實是殘酷的。

Android Developers關於dp的文檔我看過N次,那個px和dp的轉換公式我記得很清楚: px = dp * (dpi / 160),可是今天翻了源碼了才發現,原來這裡的dpi是歸一化後的dpi,可能值只有120(low)、160(medium)、240(high)、 320(xhigh)四種,而我之前理解的竟然是實際裝置真實的dpi!

G7的真實dpi是252,根據我以前的理解,310dp換算成px應該是:310 * (252 / 160) = 488像素,而G7水平方向是480px,310dp在這上面絕對滿屏都不止了,事實上Android系統並沒有拿252作為dpi來計算,而是將G7視 作hdpi裝置,然後使用240dpi來計算最終像素,所以在G7上320dp剛好是:320 * (240 / 160) = 480像素,剛好滿屏了,310dp確實要差一點點。

搞清楚這個問題後,我心裡稍微好受點了,可是另一個問題接踵而來:
dp的本質還是物理尺寸,難道不是嗎?儘管Android系統對待dp這事上,將所有裝置視為四種:120(low)、160(medium)、 240(high)、320(xhigh),在160dpi上,160dp就是1英寸,在240dpi上,160dp還是1英寸,120dpi和 320dpi也還是1英寸,雖然他們佔用的像素數不一樣,但是最終顯示出來的效果都是佔用了螢幕上1英寸的範圍。這套體系其實是非常合理的,一個寬為 160dp的按鈕,它在所有裝置上佔用的物理尺寸應該是一樣大才合理,這樣他們對人眼所形成的張角才一樣大,觀看或者閱讀的感覺才一致(姑且不考慮按鈕的
背景是否一樣細緻)。這應該是Android系統引入dp概念的原因,因為手機螢幕的像素密度相差實在太大了,web那套東西已經完全不適用,你想電腦屏 幕的像素密度能相差多大?

終極問題來了,現實生活中真的只有以上四種不同像素密度的裝置嗎?不可能。雖然所有這些裝置都可以粗略地劃分為low、medium、high、 xhigh四種密度,可是對於劃在同一範圍內但具有不同像素密度的兩個裝置來說,同樣的dp最終所佔用的物理尺寸是不一樣的。舉個例子,G7(HTC Desire)的螢幕尺寸是3.7英寸,解析度是480*800,像素密度是252dpi,G10(HTC Desire HD)的螢幕尺寸是4.3英寸,解析度同為480*800,像素密度是217dpi。假設現在有一個按鈕,它的寬度設為100dp,由於G7和G10同被
劃分為hdpi,那麼在這兩個裝置上,這個按鈕的實際寬度是:100 * (240 / 160) = 150像素,可由於這兩個裝置的實際像素密度是不一樣的,所以真實的顯示效果是:這個按鈕在兩個裝置上的實際物理尺寸是不一樣大的。而這,和 Android進入dp的概念是相悖的。

你可以說對於同屬於hdpi的裝置而言,這個差別很小,但是在ldpi和hdpi之間這個差別就很明顯了。我非常認同,可是如果在將dp轉化為px的時 候,不是使用歸一化dpi(也就是120(low)、160(medium)、240(high)、320(xhigh)這四種),而是使用裝置真實的像 素密度,那麼得出的像素數目雖然各不一樣,但是最終顯示出來的物理尺寸確實一樣大的,而這種計算方法,我認為是忠於像素密度無關的理論的。

最後我還是想說,如果Android希望一個寬度為160dp的按鈕在任何裝置上都是1英寸大,那為什麼不直接使用英寸作為度量單位呢?如果你有好的想法,歡迎留言。

UPDATE:

今天下午在回答factar網友的問題的時候,我上面那個“終極問題”終於找到了一個合理的答案。在factar貼的網址裡,我發現一句重要的話:

“However, bitmap scaling can result in blurry or pixelated bitmaps, which you might notice in the above screenshots.”

這句話的意思是說,圖片資源在縮放的時候會造成映像模糊。按照我以上的分析,如果為了保證相同的圖片資源在不同像素密度的裝置上保持完全一樣的尺寸 大小(這完全可以做到,在dp轉化成px的時候使用裝置的物理像素密度參數),那圖片在不同裝置上的縮放因子必然不一樣,而這會導致映像模糊!所以我猜想 Google為了保證了映像不會模糊退了一步,讓相同dp在不同裝置上“差不多一樣大”。

還有,這個答案也糾正了我的一個誤區,現在有很多應用程式開發商為了降低安裝包的大小,只使用一套hdpi資源或者一套xhdpi資源,而不提供 mdpi資源或ldpi資源,希望在mdpi和ldpi裝置上有系統完成縮放適應,雖然可行,但是我們不應忽視因為縮放帶來的映像模糊、顯示效果不佳的現象。

網友問答參考:
不知eggclam現在是否對dp有了更深入的理解,我現在對dp這裡也陷入到了這步,我現在有三個pad,一個10寸,2個7寸,
參數如下:
A:7寸pad 1,
denstiy:1.0 解析度 1024X600
B: 7寸pad 2,
denstiy: 1.33 解析度 1280X800
C: 7寸pad 3,
denstiy:1.0 解析度 1280X800

按照google 官方文檔稱(http://developer.android.com/guide/practices/screens_support.html)
Density independence 段落,用dp在不同的denstiy 下,大小看起來應該是一樣的。
我在三個pad 都設定了同樣dp長度的按鈕,但是在3個pad上的長度看著都不一樣,不知道是因為什麼呢?能不能加你好友討論下呢?

引用“factar”的評論:不知eggclam現在是否對dp有了更深入的理解,我現在對dp這裡也陷入到了這步,我現在有三個pad...

C 裝置應該是10寸吧?

如果C 裝置是10寸,那麼這三款裝置的物理dpi大致如下:
A:169.5
B:215.6
C:150.9

根據這裡的劃分(http://developer.android.com/guide/practices/screens_support.html#range),A和C被評價為mdpi(density=1.0),B本來應該被評價為hdpi(density=1.5),但是自從API LEVEL 13開始Android引入了DENSITY_TV(dpi=213),而且你貼的資料也的確證明這一點,所以B裝置的density沿用你的資料1.33

接下來我們算算一根50dp的線條在這三個裝置上顯示成多少像素:
A:50 * 1.0 = 50(px)
B:50 * 1.33 = 67(px)
C:50 * 1.0 = 50(px)

接下來的問題就簡單了,問題直接轉化成這三個像素值在ABC上佔用的物理尺寸一致嗎?我們可以算算:
A:50 / 169.5 = 0.2950(英寸) = 0.7493(厘米)
B:67 / 215.6 = 0.3108(英寸) = 0.7894(厘米)
C:50 / 150.9 = 0.3313(英寸) = 0.8418(厘米)

根據以上結果,你看到的不完全一樣大是合乎情理的,因為在Android中,相同dp在所有mdpi裝置上雖然像素數量是一樣的,但是因為各個裝置物理dpi不一樣,所以在最終的顯示尺寸上是有微弱差別的。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.