深入理解Android的密度独立性

?
尺寸单位在安卓中,用户界面可以在xml文件中创建或在在代码中实现。有几种单位可以用来表示一个表单的长宽。它们可以用在很多元素上来设定宽、高、外间距、内间距等等。
px——屏幕上真实的像素。这是一个与像素密度有关联的单位,一px单位的物理大小取决于屏幕的像素密度。
in——屏幕上的物理英寸。这是一个与像素密度无关联的单位,一in单位的物理大小在任何像素密度的屏幕上都是一样大的。一in单位转化为多少px单位取决于屏幕的像素密度。
mm——屏幕上的物理毫米。这是一个与像素密度无关联的单位,一mm单位的物理大小在任何像素密度的屏幕上都是一样大的。25.4mm等于一in。一mm单位转化为多少px单位取决于屏幕的像素密度。
pt——点,屏幕上普通字体大小单位。这是一个与像素密度无关联的单位,一pt单位的物理大小在任何像素密度的屏幕上都是一样大的。72pt等于一in。一pt单位转化为多少px单位取决于屏幕的像素密度。
dp——像素密度无关联的像素单位。这是一个与像素密度无关联的单位。然而一dp单位的物理大小在不同的像素密度屏幕上只是近视的相等。大约160dp等于一in。在一dp转化为160dpi中的一个比例因子是与设备的密度级别相关联的。一dp等于多少像素取决于屏幕的像素密度和设备所属的密度级别。
sp——大小独立的像素单位,特地指定text的大小。这是一个与像素密度无关联的单位。然而一sp单位的物理大小在不同的像素密度屏幕上只是近视的相等。在一sp转化为160dpi中的一个比例因子是与设备的密度级别以及字体表现的大小相关联的。一sp等于多少像素取决于屏幕的像素密度和设备所属的密度级别。?
上面的表格显示了100 dp如何在不同密度的设备上转换为"px"。100 dp应该大致地转化为0.625 in,并且完美地转换为bucket sizes。但是,当设备的dpi少于密度桶的dpi的时候,它的像素在物理上会更大,并且相同数目的"dp"会渲染得更大,反之亦然。
因此这就引出一个问题,为什么"dp"允许这种物理尺寸的变化?从根本上来说,android在物理尺寸上会牺牲一些精确度,目的是为了保持性能和显示质 量。由于利用android的密度桶比率(0.75:1.0:1.5:2.0:3.0)让"dp"缩放到"px",这就允许有极小的"px"舍入和简单的 估计。同时,由于缩放因子与密度桶比率成比例,“dp”会按比例显示为各种密度提供的图片资源。最后,当缩放图行的时候,最好保持接近整数和简单的分数,因为复杂的分数会导致图片颜色过渡异常和走样。
?
定义UI元素的界限
当定义用户界面元素的长宽时有几个特别的选项可供选择,就像尺寸单位一样。
wrap_content——这个选项将会扩展元素的边界到足够的大小以致可以容纳它包含的内容(图片,文本等等),本质上,这个选项把元素设置成它最大子元素的大小,不会去调整元素的大小。
match_parent(fill_parent 在API 8中已过时)——这个选项会使元素适应父元素的大小,使用父元素最大的空间,减少间距。本质上,这使子元素为父元素允许的最大尺寸的大小,并且必要的时候会调整元素的大小。
dimension unit——这个选项设置元素的边界为精确地单位大小,这些单位上文已经讨论过。本质上,它会设置元素的边界为确定的单位大小,必要的时候会调整元素的大小。?? ? ? ? ? ? ? ? ? ? ? ?密度为xhdpi (320dpi),200x200px 的图片
? ? ? ? ? ? ? ??
在计算完所需特定密度的图像尺寸后,他们能够在最大密度版本被缩小到相应的尺寸,如前面所解释的那样。接下来,每一个密度版本的图片,能够被放入到用相应资源标识符标记的“drawable”文件夹下。Android系统会根据设备上的配置,在运行时选择最佳的资源。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?有标识符的资源目录
现在,为了呈现保持密度独立的可能方式,利用每一种密度独立的尺寸单位,将该图片设置成相同的物理尺寸。因为"px"不是密度独立的,而"sp"是为text设计的,因此忽略它们。
? ? ? ? ? ? ? ? ?
?
?
?320dpi 模拟器截图
? ? ? ? ? ?Galaxy Nexus 截图
?
经过检查发现,很显然用"wrap_content"和"dp"设置的图片在大小上是匹配的,与此同时,用"in","mm"和"pt"也是匹配的。但 是,这两组没有彼此匹配。到底发生了什么事情呢?如之前讨论,"wrap_content"和"dp"利用密度桶比率去适当地转换它们的尺寸。因此,图片 大小被计算到200x200 px。但是,Galaxy Nexus的实际屏幕密度并不是320 dpi,它是 315.3 xdpi和 318.7 ydpi。 因为实际的密度低于320 dpi的xhdpi密度,因此在实际设备上的像素点会比想象的0.625 in的物理大小更大。
当分析用"in","mm"和"pt"设置图片大小的时候,注意到每一个图片被转换为 197.1x199.2 px。如之前讨论,"in","mm"和"pt"都是利用实际设备的密度去转换它们的尺寸到像素。因为Galaxy Nexus的实际密度低于320 dpi的xhdpi密度,更少的像素需要被转换为0.625x0.625 in,这样图片就被缩小了。
当对所显示的图片进行对比时,很明显,用"wrap_content"和"dp"设置的图片物理尺寸精确度较低,但是它们的图片质量比"in","mm"和"pt"更好。

没有缩放"wrap_content"和"dp"(左)。有缩放"in","mm"和"pt"(右)
?
?
设备例子: hdpi Bucket下一步,当运行在240dpi的模拟器上时,图片以完全相同的大小显示每一个尺寸单元。重复一下,之所以期望这样是由于模拟器的dpi在240dpi的条 件下恰好匹配hdpi密度的桶(bucket)。但像以前一样,当运行于hdpi设备时,出现一个不可思议的事情,图像的尺寸有一些变化。

?
?
240dpi模拟器屏幕截图
???????????????????????????? 
?
就像在Galaxy Nexus上,用"wrap_content"和"dp"设置的图片物理尺寸精确度较低,但是它们的图片质量比"in","mm"和"pt"更好。

没有缩放"wrap_content"和"dp"(左)。有缩放"in","mm"和"pt"(右)
你能在GitHub找到该demo所有的源码,或从后面的附件中获得。
?
尺寸单位最佳实践px-?没有保持密度独立。应该永远不需要。
in/mm/pt- 保持密度独立,但是计算到确切数额的像素,会降低体验,还会导致图片颜色过渡不自然和走样。如果需要尺寸大小的精确度,并且任何偏差都是不可接受的,那选择in/mm/pt就是必要的。需要确切距离的时候,设置元素间的距离,in/mm/pt也是很有用的。
dp- 保持密度独立并且保持最佳图片质量,但是要在物理大小上,以小的偏差作为代价。因为它利用密度桶比率来进行计算大小,它适当地提供准确的尺寸与图片资源。这是被推荐使用的尺寸单位,用来设置元素间的界限或者之间的距离。
sp- 保持密度独立和字体的质量,但是要在物理大小上,以小的偏差作为代价。这是被推荐使用的尺寸单位,仅仅用来设置字体大小,因为它需要考虑密度和用户的文本大小偏好。
?
?
总结总的来说,保持密度独立性的要点:
确定每一个图像资源确定呈现该资源所需的物理尺寸设计尺寸比最大密度桶更大的矢量图像资源或原始图像资源为每一个密度桶创建特定的density 版本,然后将他们放入用合适标识符标识的“drawable”资源目录下当设置图像边界的时候,用“wrap_content”来获得最佳显示效果,用“match_parent”来充满整个显示区域,或者用“dp”来设定一个固定的尺寸当在布局里面设定距离的时候,用“dp”获得最佳显示效果。如果需要使用精确的尺寸,仅用“in”,"mm"或"pt"。在这里永远别使用"px"随着对Android如何处理在不同密度的屏幕上显示的理解,这将使得在任何密度的显示屏上设计和开发最佳的应用程序变得更加容易。
?
英文原文:Understanding Density Independence in Android? 翻译:OSchina?
?
?
