`
亚当爱上java
  • 浏览: 697568 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

android中的dp,px深度解析

阅读更多
  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就差一点点满屏。

   我的手机是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不一样,所以在最终的显示尺寸上是有微弱差别的。
分享到:
评论
6 楼 utyujin 2016-10-28  
作者你好,首先自我注释一下我是一名UI设计师,最近在写关于屏幕适配的文章,因为之前在做适配的时候都是只考虑iOS,Android则只做一些大概标注,然后让程序员去把控。然而从我开始写文章的时候我就陷入混乱之中。
最初我也是和作者你一样坚信了网上的px = dip * density / 160这一套理论,然而从我自己开始去写去计算的时候,我就开始怀疑我之前的理论是错的,后来也思考过是把dp划分到几个ppi级别去计算,就如你文章里说的310dp差一点满屏。本来我自己也差点信了自己,然而当我拿出两个手机对比的时候我又绝望了,在这两个手机的同一个app里,设置的都是50dp的高度(我明确问过程序员是50dp,没有针对其中个别屏幕做过调整),但是显示的结果确是这样的:
红米note3--1080*1920--5.5inch--403ppi--50dp=150px
小米max----1080*1920--6.44inch--342ppi--50dp=138px
note3我可以理解,它就是标准的被划分到xxhdpi里,是三倍屏。
但是max我怎么算都无法理解啊,就算按px = dip * density / 160来算,那也应该是107px,这个138px到底是怎么出来的我完全无法理解。
于是我就上网各种地方去找,然而网上的教程基本上都是各种错误的教程我抄你你抄我,或者答非所问说sketch一键导出帮你解决所有烦恼。就在我打算放弃的时候 看到作者你的这篇文章,于是冒昧来问一下,虽然也不知道你会不会看到这个评论。如果看到了希望能给一些指导,我的qq:2528844735(q名:utyujin)。
另外我写的文章在这里http://www.zcool.com.cn/article/ZNDQxMzI0.html,可能你看到我评论的时候我会做了其他更新。我也会在我的文章下评论引用你这里的文章,非常感谢!
5 楼 圣经未来 2016-04-22  
虽然帖子距今已有三年,但是我还是来评论一下。对于这段话:
这句话的意思是说,图片资源在缩放的时候会造成图像模糊。按照我以上的分析,如果为了保证相同的图片资源在不同像素密度的设备上保持完全一样的尺寸 大小(这完全可以做到,在dp转化成px的时候使用设备的物理像素密度参数),那图片在不同设备上的缩放因子必然不一样,而这会导致图像模糊!所以我猜想 Google为了保证了图像不会模糊退了一步,让相同dp在不同设备上“差不多一样大”。

对于这一段感觉有问题。
如果有一个图片是190px*190px的,我ImageView是100dp*100dp,如果本身的缩放因子是1.9,那么我计算出的图像正好是190px*190px的,但是如果缩放因子要统一,那么系统会认为值2.0,反而把图片改为200px*200px了,那岂不是多此一举了?
4 楼 passerby_whu 2015-02-09  
u013023750 写道
楼主你好,今天拜读了您的文章,收益匪浅。
但是我和你的思路有些许不同,写下来,请大家批评指正。、

android推荐大家用dp作为单位来度量控件的大小,我个人认为,其目的是追求,此控件相对于整个屏幕的大小一致,或者说此控件和屏幕的比例,在各种设备上都一样。

楼主一直以物理尺寸作为标准,来衡量这套体系,似乎有些偏颇。

因为,我们试想,同样物理大小相同的控件,在不同尺寸的设备上给人的观感是不同的。
打个比方吧,就像如果为了保持物理尺寸的大小,把健身运动员过分粗壮的胳膊,按在我们这样平常人的身体上,肯定不协调,人只会看起来比之前丑陋了,因为不协调。
只有我们自己的胳膊适合我们的身体,因为其和整个身体的比例更协调,因而更好看。

因此,我个人认为,android的追求的是控件和屏幕的比例一样。

下面是我的两张笔记,因为很多东西用文字不好表达,所以我就用两张图吧。


如果android朋友们有任何问题,欢迎和我讨论,我qq是527501779




你的个人认为没有任何实际数据支撑。
根据官方的换算公式。 px=dp*(dip/160)。
那么在160dip的设备上,160dp就是160px,也就是1 inch。
在320dip的设备上,px=160dp*(320/160)=320px,也就是1 inch.
在80dip的设备上,px=160dp*(80/160)=80px,也就是1 inch。
320dip和80dip的设备可以看成是160dip的设备分辨率不变,尺寸缩小一半,和放大一倍。
很明显的就是物理尺寸一致。哪有什么保持比例一致?

如果真要保持比例一致,那么在320dip的设备上就应该只有0.5 inch,而在80dip的设备上应该有2 inch。
3 楼 u013023750 2014-05-05  
楼主你好,今天拜读了您的文章,收益匪浅。
但是我和你的思路有些许不同,写下来,请大家批评指正。、

android推荐大家用dp作为单位来度量控件的大小,我个人认为,其目的是追求,此控件相对于整个屏幕的大小一致,或者说此控件和屏幕的比例,在各种设备上都一样。

楼主一直以物理尺寸作为标准,来衡量这套体系,似乎有些偏颇。

因为,我们试想,同样物理大小相同的控件,在不同尺寸的设备上给人的观感是不同的。
打个比方吧,就像如果为了保持物理尺寸的大小,把健身运动员过分粗壮的胳膊,按在我们这样平常人的身体上,肯定不协调,人只会看起来比之前丑陋了,因为不协调。
只有我们自己的胳膊适合我们的身体,因为其和整个身体的比例更协调,因而更好看。

因此,我个人认为,android的追求的是控件和屏幕的比例一样。

下面是我的两张笔记,因为很多东西用文字不好表达,所以我就用两张图吧。


如果android朋友们有任何问题,欢迎和我讨论,我qq是527501779
2 楼 yung7086 2014-03-31  
这个文章写得很好 让我也更深了解了下子 先顶下楼主,然后问个问题“那图片在不同设备上的缩放因子必然不一样,而这会导致图像模糊”这句话为什么说缩放因子不一样会导致图片模糊?这点不明白期望楼主能解释 理解菜鸟路上的急切
1 楼 yung7086 2014-03-31  
这个文章写得很好 让我也更深了解了下子 先顶下楼主,然后问个问题“那图片在不同设备上的缩放因子必然不一样,而这会导致图像模糊”这句话为什么说缩放因子不一样会导致图片模糊?这点不明白期望楼主能解释 理解菜鸟路上的急切

相关推荐

Global site tag (gtag.js) - Google Analytics