Android图片资源

概述:
本文整理了Android开发中,图片资源的提供方式和使用方式。包括图片文件的文件组织,nine-path图片,系统选择不同设备针对的图片时的规则等。可以在Android开发文档中,Develop > API Guide > App Resources 目录找到有关应用资源的更全面的介绍。
Note: 在Android 3.2之后的版本,有新的资源组织方式,本文只侧重关于早先的资源的组织方式的整理。

1.为什么提供不同设备配置的资源文件

除代码外,资源文件也是安卓程序中必不可少的部分,如图片、布局文件,甚至是音频、视频等原始多媒体文件。不同于代码文件的是,UI资源文件是和设备的显示器密切相关的。目前,Android设备的配置种类繁多——不同的屏幕尺寸,分辨率,以及用户使用时的不同的屏幕方向等。为了让自己的程序运行在多种不同的尺寸上都表现良好,Android系统提供了很多有用的方式。例如,为不同的尺寸和分辨率的屏幕提供不同的图片资源,这样可以让你的应用在不同的设备上显示最适合此设备分辨率/尺寸的不同大小的图片。
总之,在UI表现上,考虑为不同设备提供不同的资源是必不可少的做法。

2.Android屏幕配置相关概念

2.1 像素pixel/px

像素就是显示器上显示的一个最小的点,整个显示屏就是一个由像素点组成的矩形。例如720*1280的像素就是说屏幕在横竖分别有720和1280个可显示的点。目前来讲像素点都是一个正方形的“点”,它是最小的显示单位。

2.2 PPI

Pixels Per Inch:每英寸的像素数,表示每英寸所拥有的像素数量。因此PPI数值越高,即代表显示屏能够以越高的密度显示图像。

2.3 DPI

Dot Per Inch:每英寸的点数。这里的“点”是一个抽象概念,例如打印机中,点就是。。。在电子显示器中,DPI和PPI通常是混用的。

DPI和PPI都是描述设备的显示密度的,它们本身不是长度单位,而是一个密度系数。

2.4 像素密度

Android中对图片的分类是通过Screen pixel density (像素密度:以dpi为数值单位)进行的,包括ldpi、mdpi、hdpi、xhdpi这四个主要的级别。
ldpi: Low-density screens; approximately 120dpi.
mdpi: Medium-density (on traditional HVGA) screens; approximately 160dpi.
hdpi: High-density screens; approximately 240dpi.
xhdpi: Extra high-density screens; approximately 320dpi。
xhdpi:480dpi。

这四种屏幕密度之间存是3:4:6:8的缩放比例,所以,一个ldpi下的9x9像素的bitmap(位图)在mddpi下就是12x12,在hdpi下是18x18,在xhdpi下是24x24。

2.5 Android对屏幕的分类

Android用两个属性size和density来对屏幕分类:
屏幕尺寸:small, normal, large, xlarge,xxlarge。

  • xlarge :screens are at least 960dp x 720dp
  • large screens are at least 640dp x 480dp
  • normal :screens are at least 470dp x 320dp
  • small :screens are at least 426dp x 320dp

像素密度:low (ldpi), medium (mdpi), high (hdpi), extra high (xhdpi), extra extra high (xhdpi)。

屏幕尺寸和像素密度都有各自的分级,它们是相互独立的。大屏幕可以是小的分辨率,而小屏幕可以是大分辨率。

2.6 DP的使用

对于Android开发,布局文件中可以使用px(pixel像素)这样的绝对单位,而更多情况下,根据Android开发的适配方式,应使用的UI元素的大小单位是“dp”即“dip”,device independent pixels(设备独立像素)。
它是一个虚拟的像素单位,以像素无关的方式来表示UI元素的尺寸和位置。
设备最终显示时,UI上的任何元素都是需要一个具体的像素值的,那么dp是如何转换为最终的像素值的?
正如DIP它的名字,它表示一种逻辑单位,和实际pxiel之间存在着转换关系,系统会自动在不同设备像素密度时把以dp为单位的大小缩放为合适的具体像素值。
具体做法是:

像素密度分级mdpi为基准,它的dpi值为160,此时1dp = 1px。对于运行程序的设备,Android系统会根据其尺寸和屏幕像素来计算出它的像素密度分级。不同像素密度下dp和px的转换不同,公式是: px = dp * (dpi / 160),根据公式可以知道,不同像素密度下的dp转换为px时对应的缩放比例和它们之间的dpi值是成正比的。那么在xhdpi下,其dpi为320,则1dp为2px,正好是mdpi的2倍。

下面是bitmap的例子:
在为应用提供bitmap资源时,应该保证图片可以正确被缩放到不同的像素密度级别。
对于一个图片,它在不同像素密度级别下的缩放系数如下:

  • xhdpi: 2.0
  • hdpi: 1.5
  • mdpi: 1.0 (参考标准)
  • ldpi: 0.75

如果在xhdpi的设备下使用的合适的图片尺寸是200x200,那么在hdpi下图片应该是150x150,在mdpi下是100x100,在ldpi下是75x75.

目前手机的像素密度至少都在mdpi及以上,所有通常只提供xhdpi和xxhdpi下的图片即可,像素密度小的设备,Android系统会将位图进行合适的缩放。

以dp为尺寸和位置,使得UI元素在不同屏幕上拥有一致的表现。原理就是“等比缩放”,方式就是dp,dp的概念和对应px的计算方式如上面所记。即便使用dp来在不同的dpi下进行缩放转换,如果屏幕的大小(例如同样的dpi但是一个是5寸、一个是8寸平板)、宽高比例(4:3、16:9、16:10等)是不一样的,还是会出现个别的UI显示问题。这就需要借助良好的UI布局设计来避免内容显示不全、错位...等问题。对于形形色色的屏幕,没有一种方案是万能的。

优缺点:
等比缩放:位图失真,没有充分利用大屏幕显示更多的内容。
不等比缩放:满足宽高都显示完整,其余的和等比缩放一样。
灵活的布局排版:设计上去避免不同尺寸的屏幕显示问题最好。

2.7 size和density资源组织的不同

The types of alternative resources you should create depends on your application's needs. Usually, you should use the size and orientation qualifiers to provide alternative layout resources and use the density qualifiers to provide alternative bitmap drawable resources.
为不同尺寸的屏幕提供不同特定的layout文件,对不同的像素米的屏幕提供不同的drawable资源。

3.多个备选图片资源的组织

以dp指定的宽高和位置数值,系统会自动缩放到合适的像素数值。对于drawable 资源(bitmap: .png, .jpg, and .gif 、Nine-Patch: .9.png),系统也会根据当前的设备像素密度来对它进行缩放——当为ImageView这样的控件指定以dp为单位的大小,或者为wrap_content时,在不同的像素密度的屏幕上其显示的像素大小是不一样的。若只提供单一的图片资源,在缩放后图片往往会变得模糊与期望不一样,所以图片,尤其是位图,需要针对不同的像素密度来提供不同的合适的像素尺寸的图片。
所以,需考虑对不同的像素密度的屏幕提供不同的图片资源。在Android项目中,图片资源的组织,正是按照pixel density来进行不同屏幕的分组。
drawable 资源放在res目录下不同的子目录中——使用不同的像素密度修饰符对应不同的像素密度:

  • drawable-ldpi/ :对应ldpi
  • drawable-mdpi/ :对应mdpi
  • drawable-hdpi/ :对应hdpi
  • drawable-xhdpi/ :对应xhdpi
  • drawable-xxhdpi/ :对应xxhdpi

根据应用需要适配的屏幕范围,提供对应的图片资源到drawable-(density qualifiers)目录下。

Note: You only need to provide density-specific drawables for bitmap files (.png, .jpg, or .gif) and Nine-Path files (.9.png). If you use XML files to define shapes, colors, or other drawable resources, you should put one copy in the default drawable directory (drawable/).

4.系统对图片资源的选择规则和使用方式

对应一个代码中用到的图片资源,Android系统会使用以下步骤来选择出最适合当前运行设备的图片资源文件进行显示:

  1. 系统寻找匹配当前屏幕像素密度的可用图片文件。
    例如当前设备屏幕像素密度分级为xhdpi则使用drawable-xhdpi目录下的文件。
  2. 如果没有找到匹配的文件,系统使用默认的图片资源,并对它进行缩放。
    系统会使用合适的图片,进行缩放。例如,设备像素密度为ldpi,应用提供了hdpi的图片,那么系统会选择对hdpi的图片缩放0.5。最后的情况是,如果没有任何与当前像素密度合适的图片,系统选则默认的default resources(目录不包含配置修饰符,即drawable目录)——对应mdpi的像素密度。

为不同的密度的屏幕提供图片时,确保在统一的几个密度分级之间按照3:4:6:8的比例。
例如,假设在mdpi下提供的launcher icon为48x48像素,那么在其它密度下的尺寸分别为:

  • 36x36 for low-density
  • 48x48 for medium-density
  • 72x72 for high-density
  • 96x96 for extra high-density

5.UI适配的技巧

5.1 指导

  • Use wrap_content, fill_parent, or dp units when specifying dimensions in an XML layout file ,Similarly, you should prefer the sp (scale-independent pixel) to define text sizes. The sp scale factor depends on a user setting and the system scales the size the same as it does for dp.
  • Do not use hard coded pixel values in your application code
  • Do not use AbsoluteLayout (it's deprecated)
  • Use size and density-specific resources,Supply alternative bitmap drawables for different screen densities.

5.2 代码中dp和px的转换

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);
}

6.Nine-Patch图片的使用

Android中提供两种方式在屏幕上绘制图像:Canvas、和Drawable。
Canvas: 代码中继承自View后重写onDraw等方法。
Drawable:resource images、resource XML、ShapeDrawable和Nine-patch。

静态图片资源(可以是多种备选)中.9.png是特殊的一种,在UI适配时很常用。

如果UI中使用到的位图需要在系统拉伸某个View之后依然填充此View(例如按钮的背景图片),那么就应该使用NinePatch图片,它的指定的部分可以被任意拉伸。所以,使用一个NinePatch就可以适配所有尺寸的屏幕。不过,对不同的密度的屏幕,依然需要提供不同的NinePatch。

九宫格图片是一种可拉伸的位图,在作为其它View的背景显示时,Android系统会自动将它改变到一个合适的大小。例如一个Button的长度随其显示的文本变化时,作为Button的背景的NinePatch图片也会自动被拉伸。
九宫格图片是一个标准的png文件,它包含一个额外的“1-像素-宽度”的边界。九宫格图片的名称必须以 .9.png作为后缀。针对不同像素密度的NinePatch图片放在不同的drawable-xxx里面。

NinePatch的边界用来定义它的可拉伸区域和静态区域(内容填充区域),通过在左、上边界上指定一个或多个1-pixel-wide黑色的线段——线段上的像素点就是可以在拉伸时被重复的点。这些线段在拉伸时保持相对的大小。

右、下边界可以分别指定1个线段(不能是多个)来确定背景的内容填充区——也就是View的内容可以填充的区域,类似padding地作用。如果不指定,那么系统以边长除去两边一像素的线段作为填充区域的线段。

由于Nine-patch图片的特殊使用方式,应该注意它的最小尺寸,保证有一个点的可拉伸区域。例如一个10像素半径的圆角矩形,边长至少为21,其中一个点是拉伸区域。

参考资料

在Android开发文档 4.4 中:

  • API Guide > Animation and Graphics > Canvas and Drawables
    ./sdk/docs/guide/topics/graphics/2d-graphics.html

  • API Guide > App Resources > Providing Resources
    ./sdk/docs/guide/topics/resources/providing-resources.html

  • API Guide > Best Practices > Supporting Multiple Screens
    ./sdk/docs/guide/practices/screens_support.html

  • Training > Getting Started > Supporting Different Devices
    ./sdk/docs/training/basics/supporting-devices/screens.html

  • Design > Style > Iconography
    ./sdk/docs/design/style/iconography.html

  • Training > Best Practices for User Interface > Designing for Multiple Screens
    ./sdk/docs/training/multiscreen/index.html

posted @ 2016-05-10 17:40  everhad  阅读(660)  评论(0编辑  收藏  举报