程序员人生 网站导航

Android的屏幕多样性支持

栏目:综合技术时间:2016-03-23 08:47:06

前言




运行Android系统装备的屏幕尺寸和密度千变万化。但是对利用程序来讲,Android系统为所有装备提供了1个统1的开发环境,并且由系统处理了大部份利用程序界面与实际屏幕的适配工作。同时,系统也提供了相应的API允许你在特定的屏幕尺寸或屏幕密度上为你的利用程序UI做特定的调剂,以便在不同配置的屏幕上优化你的UI。例如,你可能需要在平板和手机上显示不1样的UI效果。

虽然系统能够自动将你的利用程序UI通过缩放或重置大小来适配不同的屏幕,但你依然需要为你的利用程序适配不同尺寸和密度的屏幕做1点优化工作。这样,你才能够最大程度优化不同装备上的用户体验,让你的用户相信你的利用就是为他们的装备设计的,而不是通过简单的UI拉伸来填充他们的装备屏幕。

通过本文介绍的方法,你能够创建1个显示正确的利用程序,并且签名打包出1个在其所有支持的装备屏幕上都能取得优越用户体验的apk文件。

注意: 本文所有内容都假定你的利用程序只支持Android 1.6(API Level 4)或更高的Android版本。如果你的利用程序需要支持Android 1.5或更低的版本,请先浏览Strategies for Android 1.5.

另外,要知道从Android 3.2开始引入了很多新的API,这些API能够让你为不同屏幕尺寸更好的调剂利用程序所使用的layout资源。如果你开发的利用需要针对平板进行优化,这些新特性就更加重要。更多的细节可以参考下面Declaring Table Layouts for Android 3.2章节。


屏幕支持概览(Overview of Screens Support)




本章节为Android支持多样屏幕的概述。包括对本文档或API中触及的术语及概念进行介绍说明,对Android系统所支持的屏幕配置属性的总结,和API和底层屏幕兼容特性的概述。

2.1 术语及概念(Terms and concepts)

2.1.1 Screen size(屏幕尺寸)

实际的物理尺寸,根据屏幕的对角线来丈量。

为了简单起见,Android将全部屏幕尺寸归类成4种通用尺寸:small、normal、large、extra-large。

2.1.2 Screen density(屏幕密度)

指的是屏幕上1个物理单位区域中的像素数量,通常使用dpi(每英寸多少点)为单位。例如,相对“normal”或“high”密度的屏幕,在相同物理区域上“low”密度的屏幕具有的像素要更少。

为了简单起见,Android将全部屏幕密度归类成6中通用密度:low、medium、high、extra-hight、extra-extra-high、extra-extra-extra-high。

2.1.3 Orientation(屏幕方向)

屏幕的方向是从用户的视觉角度来讲的。屏幕方向不是landscape(横向)就是portrait(竖向),分别意味着屏幕的宽高比更宽或更高。注意不单要做不同屏幕的适配,还要做同1个屏幕不同方向情况下的适配,由于如果用户在利用程序运行的进程中旋转装备可能会引发屏幕方向的改变。

2.1.4 Resolution(分辨率)

表示1块屏幕上总的物理像素数量。当支持多样屏幕适配的时候,利用程序不直接使用分辨率,利用程序应当使用上文所说的系统通用尺寸和通用密度种别,只需关心屏幕尺寸和密度就能够了。

2.1.5 Density-independent pixel(dp,密度无关的像素)

1种虚拟的像素单位。当你在UI的layout资源中定义layout的尺寸或位置的时候,你应当使用这类虚拟像素单位。

1个单位的虚拟像素等于160dpi屏幕上的1个物理像素点,这也是系统将“medium”屏幕密度作为基准密度的缘由。在运行的时候,如果有需要,系统会基于实际屏幕的密度对dp单位进行缩放。dp单位和实际屏幕px像素单位的转换很简单:px = dp * (dpi/160)。例如,在240dpi的屏幕上,1dp等于1.5px。当你定义利用程序UI的时候,你应当使用dp来保证你的UI能够正确显示在不同的屏幕上。

2.2 屏幕支持的范围(Range of screens supported)

从Android 1.6(API Level 4)开始,Android提供了多种屏幕尺寸和密度的支持,以对应不同的装备屏幕配置。你可使用系统提供的这些功能针对每种屏幕配置优化你的利用程序界面,确保你的利用程序能够在每种屏幕上提供最好的用户体验,而不单单只是基本正常显示。

为了简化你为不同屏幕适配用户界面的工作,Android将实际的屏幕尺寸和密度归类为以下:


  • 4种通用的尺寸:smallnormallargexlarge


注意: 从Android 3.2(API Level 13)开始,这些尺寸分类已被弃用,以便于基于可用屏幕宽度来管理屏幕尺寸这类新技术的实现。如果你是为Android 3.2或更高版本的系统开发,请参考下面 Declaring Tablet Layouts for Android 3.2 章节获得更多信息。


  • 6种通用密度:
    • ldpi(low) ~ 120dpi
    • mdpi(medium) ~ 160dpi
    • hdpi(high) ~ 240dpi
    • xhdpi(extra-hight) ~ 320dpi
    • xxhdpi(extra-extra-high) ~ 480dpi
    • xxxhdpi(extra-extra-extra-high) ~ 640dpi


这些通用尺寸和通用密度全部都是以normal尺寸和mdpi密度作为基准来调剂的。之所以使用这个基准是由于这是第1部Android装备T-Mobile G1的屏幕配置,也就是HVGA屏幕(直到Android 1.6之前,这都是Android唯1支持的屏幕配置)。

每套通用尺寸和通用密度都会覆盖1定范围的真实屏幕尺寸和密度。例如,两台装备都要求使用normal尺寸,但实际上手动丈量两台装备屏幕的真实尺寸和纵横比会稍略不同。一样的,两个装备都要求使用hdpi密度,但实际上两台装备的像素密度稍略不同。Android系统会将这些差异抽象化,因此你可以直接提供通用尺寸或通用密度的UI,让系统在有需要的时候自动进行校准。下图粗略的展现了不同的尺寸和密度与通用尺寸和通用密度的对应关系:

通用尺寸和通用密度对应的大致范围

图1 真实尺寸与密度和通用尺寸通用密度对应的大致范围(注意图中数字是不太准确的)

当你为不同的屏幕尺寸设计UI的时候,你会发现每种都有最小的空间值限制。因此,系统对上面提到的每种通用屏幕尺寸都定义了相干联的最小解析度。最小的尺寸为1dp,dp是你定义layout的时候应当使用的单位,使用这个单位才能让系统处理UI因屏幕密度不同引发的变化。


  • xlarge屏幕最小解析度为960dp*720dp
  • large屏幕最小解析度为640dp*480dp
  • normal屏幕最小解析度为470dp*320dp
  • small屏幕最小解析度为426dp*320dp


注意: 这些最小屏幕解析度在Android 3.0之前的版本上并没有明肯定义,因此,你可能会发现1些装备的屏幕尺寸在normal和large之间被毛病归类了。另外,这些解析度也基于屏幕的物理解析度,所以每台装备都各不相同――例如1部1024*720的平板使用了系统栏后留给利用程序的可用空间会更少,由于部份空间被系统栏占用了。

为不同的屏幕尺寸和屏幕密度优化你的利用程序UI,你可以为1些通用尺寸和通用密度提供替换的资源。通常情况下,你应当为不同尺寸的屏幕提供可替换的layout资源,和为不同密度的屏幕提供可替换的图片资源。在运行的时候,系统会将当前装备的屏幕与通用尺寸或通用密度进行对照,自动为你的利用程序选择适合的资源。

你不需要为每种通用屏幕尺寸和通用屏幕密度的组合都提供1套可替换的资源。系统提供了强大的兼容功能,能够将你的利用程序渲染到不同装备屏幕上并处理大部份的问题。但条件是你在实现你的UI时已使用了相干的技术,这样才能使系统优雅的调剂UI大小(详细请查看下面独立密度章节)。

注意: 1台装备的通用屏幕尺寸和通用屏幕密度的特性之间是相互独立的。例如,1块WVGA的high密度屏幕将会使用normal屏幕尺寸,由于它的物理尺寸与T-Mobile G11样(第1部Android装备,也是屏幕配置分类的基准)。另外一方面,1块WVGA的medium密度屏幕将会使用large屏幕尺寸。虽然它们的解析度是相同的(总像素相同),但是这块WVGA medium密度的屏幕密度比较低,这意味着它的像素点物理尺寸更大,因此才会使整块屏幕比基准屏幕(normal尺寸的屏幕)更大。

2.3 独立的密度(Density independence)

当你的利用程序实现“密度独立”时,即便是在不同密度的屏幕上,你的UI元素也将保存一样的物理尺寸(从用户的角度来看)。

保持密度独立是1件重要的事情,由于如果没有保持密度独立,1个UI元素(例如1个按钮)将会在低密度屏幕上显示的很大,而在高密度屏幕上显示的很小。像这样密度相干的尺寸如果1改变,就会致使你的利用程序产生布局或可用性的问题。图2和图3分别显示了1个利用程序如果没有保持密度独立和保持密度独立的显示效果。

没有保持密度独立效果

图2 没有支持不同屏幕密度的利用程序示例,分别是low、medium和high密度的屏幕效果。

保持密度独立效果

图3 很好支持不同屏幕密度的利用程序示例(也就是密度独立),分别是low、medium和high密度的屏幕效果。

Android系统通过两种方式来帮助你的利用程序实现密度独立:


  • 系统根据当前屏幕的实际密度自动缩放dp单位到适合的大小
  • 在需要的情况下,系统根据当前屏幕的实际密度自动缩放图片资源到适合的尺寸


在图2中,TextView和ImageView的尺寸通过像素(px单位)来指定,因此这些View的物理尺寸在low密度屏幕上显示会变得很大,在high密度屏幕上显示的很小。这是由于虽然它们的屏幕实际物理尺寸大小1样,但是high密度的屏幕上每英寸具有的像素点更多(反过来也就是一样数量的像素点在high密度屏幕上能够填充的范围更少)。由于密度无关像素的基准是medium密度的屏幕,所以在上面两张图片中medium密度的屏幕显示效果是1样的。对low密度和high密度的屏幕,系统会自动分别为dp值的实际尺寸缩小或放大到适合尺寸。

大多数情况下,确保你的利用程序与密度无关,你只需要简单的将所有layout中的尺寸值使用dp单位或“wrap_content”属性值声明。这样系统也才能够根据当前屏幕的密度选择适合的缩放因子将图片资源缩放到适合的尺寸。

但是,从上面的截图中,你可能已发现图片的缩放会致使图片模糊或产生齿距。为了不这类情况,你需要为不同的密度提供可替换的图片资源。例如,你应当为high密度的屏幕提供高分辨率的图片,系统会在high密度屏幕上使用高分辨率的图片来缩放,而不是直接使用medium密度的图片。下面的章节会详细说明如作甚不同配置的屏幕提供可替换掉的资源。


如何支持多样屏幕(How to Support Multiple Screens)




Android支持多样屏幕的基础是它能够根据当前屏幕配置适当渲染利用程序布局和图片的能力。系统正确处理了每块屏幕上的UI渲染工作,这些操作是通过缩放layout来适配屏幕尺寸/密度,或缩放图片来适配屏幕密度。为了更好的处理不同屏幕配置之间的差异,你还应当做以下工作:


  • 在manifest中明确声明你的利用程序所支持的屏幕尺寸
    通过声明你的利用程序所支持的屏幕尺寸,你可以确保只有符合屏幕配置条件的装备才能下载你的利用程序。声明所支持的不同屏幕尺寸也会影响系统如何在更大的屏幕上绘制你的利用程序――不管你的利用程序是不是运行在屏幕兼容模式下。
    声明你的利用程序所支持的屏幕尺寸,你需要在manifest文件中声明标签。

  • 为不同的屏幕尺寸提供不同的layout
    默许情况下,Android会调剂利用程序的layout大小来适配当前装备屏幕。在大多数情况下,这么做没甚么问题。但是,在有些情况下,你的UI可能看起来没那末好,需要针对不同屏幕尺寸做1定的调剂。例如,在大屏幕上面,你可能想要调剂1些元素的位置和尺寸来利用大屏幕多出来的屏幕空间,或在小屏幕上你可能需要调剂下尺寸才能让全部元素都能正确显示在屏幕上。
    提供特定尺寸资源,你可使用的配置修饰符有small、noraml、large、xlarge。例如,为extra-large屏幕提供的layout资源应当放在layout-xlarge/资源文件夹下。
    从Android 3.2(API level 13)开始,上面所说的尺寸种别已被弃用,你应当使用swdp配置修饰符作为替换品来定义你的layout资源要求的最小可用宽度。例如,如果你的多窗口平板布局要求最少600dp的屏幕宽度,你就应当使用layout-sw600dp/资源文件夹。更多关于这类声明layout资源的新技术,请参考下面Declaring Table Layouts for Android 3.2章节。

  • 为不同的屏幕密度提供不同的图片资源
    默许情况下,Android会自动缩放你的bitmap图片(.png,.jpg,和.gif文件)和Nine-Patch图片(.9.png文件),这样它们才能在每台装备上渲染出适合的物理尺寸。例如,如果你的利用程序只为基准密度,也就是medium屏幕密度(mdpi)提供了图片资源,那末系统将会在high密度屏幕上放大这些图片,在low密度屏幕上缩小这些图片。这些缩放可会到引发图片显示问题。为了确保你的图片看起来显示效果最好,你应当为不同密度的屏幕提供不同分辨率的图片进行替换。
    提供特定密度的资源,你可使用的配置修饰符(下面章节详细介绍)有ldpi(low)、mdpi(medium)、hdpi(high)、xhdpi(extra-high)、xxhdpi(extra-extra-high)、xxxhdpi(extra-extra-extra-high)。例如,想要为high屏幕密度提供的图片应当放在drawable-hdpi/资源文件夹下。


注意: mipmap-xxxhdpi修饰符只有在需要为xxdpi屏幕密度的装备提供比通常更大的启动图标时才必须使用的。你不需要为所有图片都提供xxxdpi规格的版本。

有些装备会将启动图标放大多达25%。例如,如果你的最高启动图标密度已是extra-extra-hight密度,缩放程序将会使启动图标的显示效果变得模糊。因此,你应当在mipmap-xxxhdpi资源文件夹中提供更高密度的启动图标,系统会直接使用这个图标,而不是去放大低密度版本的图片。

参考提供xxx-high密度启动图标章节获得更多详细信息。除启动图标,你不应当为其它UI元素提供xxxhdpi类型的图片。

注意: 将你的启动图标放在res/mipmap-[density]资源文件夹下,而不是res/drawable-[density]资源文件夹。由于,不管你的利用程序实际安装的装备屏幕分辨率是多少,Android系统都会保存这类密度修饰符的资源文件夹,例如mipmap-xxxhdpi。这样启动器才能够选择你的利用程序最好分辨率的图标显示在home上面。更多关于mipmap文件夹的信息,请参考Managing Projects Overview

所有的这些尺寸和密度的配置修饰符逐一对应上面屏幕支持的范围(Range of screens supported) 章节所提到的通用尺寸和通用密度。

注意: 如果你不熟习这些配置修饰符,和系统如何使用它们来适配替换资源,请参考Providing Alternative Resources。

在运行的进程中,系统通过以下几个步骤来确保UI在当前屏幕上能有最好的显示效果:


  1. 系统使用适当的可替换资源
    根据当前屏幕的尺寸和密度,系统将使用利用程序提供的对应尺寸和密度修饰符资源文件夹中的资源。例如,1台high密度的装备要使用利用程序的1张图片资源,系统将会在利用程序的全部资源文件夹中挑选最匹配当前装备配置的资源文件夹。取决于可用的替换资源,使用hdpi修饰符的资源文件夹(例如drawable-hdpi)多是最好的匹配,系统就会使用这个文件夹中的图片资源。

  2. 如果没有找到匹配的可用资源,系统将会使用默许的资源加以放大或缩小来适配当前屏幕尺寸和密度
    所谓的默许资源文件夹就是那些不带任何配置修饰符的资源文件夹。例如,drawable/资源文件夹中的资源就是默许的图片资源。系统会假定默许的资源是根据屏幕尺寸和密度的基准来设计的,也就是normal尺寸和medium密度。因此,系统将会为高密度的屏幕放大默许图片,为低密度屏幕缩小默许图片。
    但是,当系统查找对应当前屏幕的密度修饰符资源但又找不到匹配的资源时,系统不1定就会使用默许的资源。系统也有可能会使用其它密度修饰符的资源来作替换,以便放大缩小后能够获得最好的效果。例如,当系统寻觅low密度的资源但是又找不到的时候,系统会优先用high密度的资源进行缩小,由于相对使用0.75缩放因子将medium密度资源缩小成low密度资源,系统使用0.5的缩放因子将high密度资源缩小成low密度的资源会更加容易和节省开消。


更多关于Android系统如何选取带配置修饰符的可替换资源来适应装备配置信息,请参考How Android Finds the Best-matching Resource。

3.1 使用配置修饰符(Using configuration qualifiers)

Android支持1系列配置修饰符,通过这些修饰符,你可以控制系统如何基于当前装备屏幕的特性选择对应的替换资源。所谓的配置修饰符就是1串字符串,用于附加到你的Android项目资源文件夹后面,以指明该资源文件夹所针对的配置。

配置修饰符的使用方式:


  1. 在你的项目res/文件夹下创建1个新的文件夹,并以-格式命名

    • 指的是标准的资源名称(例如drawable或layout)。
    • 指的是下面表1中的配置修饰符,用于指明文件夹中的资源对应的屏幕配置(例如hdpi或xlarge)
  2. 将适当的配置资源放到对应的资源文件夹中。这些资源的名称必须与默许的资源文件1模1样。


例如,xlarge是针对extra-large屏幕的配置修饰符。当你将这个修饰符添加到资源文件夹后面时(例如layout-xlarge),它向系统指明这些资源应当用于extra-large屏幕的装备。

表1 允许你为不同屏幕配置指定资源的配置修饰符

屏幕特性 修饰符 描写
尺寸 small 针对small通用屏幕尺寸的资源
normal 针对normal通用屏幕尺寸的资源(也是所用尺寸的基准尺寸)
large 针对large通用屏幕尺寸的资源
xlarge 针对extra-large通用屏幕尺寸的资源
密度 ldpi 针对low通用屏幕密度(ldpi)的资源(大约120dpi)
mdpi 针对medium通用屏幕密度(mdpi)的资源(大约160dpi,也是通用屏幕密度的基准)
hdpi 针对high通用屏幕密度(hdpi)的资源(大约240dpi)
xhdpi 针对extra-high通用屏幕密度(xhdpi)的资源(大约320dpi)
xxhdpi 针对extra-extra-high通用屏幕密度(xxhdpi)的资源(大约480dpi)
xxxhdpi 针对extra-extra-extra-high通用屏幕密度的资源(大约640dpi)。只用于寄存启动图标,详情请参考上面章节。
nodpi 针对所有屏幕密度的资源。这些资源与密度无关,不管当前屏幕密度是多少,系统都不会放大缩小这些资源。
tvdpi 针对介于mdpi和hdpi之间屏幕密度的资源,大约是213dpi。这不是1个主要密度类型,它主要是为电视机屏幕而设置。大多数app都不需要这类类型,提供的mdpi和hdpi资源已能够满足大部份app的需求,并且在需要的时候系统也会自动对这些资源进行缩放到适合的大小。如果你需要提供tvdpi类型的资源,你需要使用1.33倍mdpi的缩放因子来设置tvdpi资源的大小。例如,1张针对mdpi屏幕的100x100px图片,对应tvdpi屏幕的尺寸是133x133px。
方向 land 针对横向屏幕的资源(宽宽高比)
port 针对竖向屏幕的资源(高宽高比)
长宽比 long 针对屏幕的竖屏或宽屏长宽比(分别对应竖向或横向方向)比基准屏幕配置更大的屏幕资源
notlong 针对屏幕的竖屏或宽屏长宽比比基准屏幕配置更小的屏幕资源


注意: 如果你的利用程序是为Android 3.2或更高的系统版本开发的,那末你需要查看下面Declaring Table Layouts for Android 3.2章节,在定义layout资源的时候使用新的配置修饰符来声明所适配的屏幕尺寸(替换表1中的尺寸修饰符)

更多关于这些修饰符如何匹配当前屏幕实际尺寸和密度的内容,请参考前面屏幕支持范围(Range of Screens Support) 章节。

例如,下面的利用程序的资源目录为不同的屏幕尺寸提供了不同的layout资源,为不同的屏幕密度提供了不同的图片,并使用mipmap/资源文件夹提供启动图标:


res/layout/my_layout.xml              // layout for normal screen size ("default")  
res/layout-large/my_layout.xml        // layout for large screen size
res/layout-xlarge/my_layout.xml       // layout for extra-large screen size
res/layout-xlarge-land/my_layout.xml  // layout for extra-large in landscape orientation

res/drawable-mdpi/graphic.png         // bitmap for medium-density
res/drawable-hdpi/graphic.png         // bitmap for high-density
res/drawable-xhdpi/graphic.png        // bitmap for extra-high-density
res/drawable-xxhdpi/graphic.png       // bitmap for extra-extra-high-density

res/mipmap-mdpi/my_icon.png         // launcher icon for medium-density
res/mipmap-hdpi/my_icon.png         // launcher icon for high-density
res/mipmap-xhdpi/my_icon.png        // launcher icon for extra-high-density
res/mipmap-xxhdpi/my_icon.png       // launcher icon for extra-extra-high-density
res/mipmap-xxxhdpi/my_icon.png      // launcher icon for extra-extra-extra-high-density


更多关于如何使用可替换资源,和完全的配置修饰符列表(不单只是屏幕配置修饰符),请参考Providing Alternative Resource.

要注意,系统在运行的时候会选择哪种资源作为“最适合”的资源是根据1定的逻辑规则来决定的。也就是,不管在哪一种屏幕下,你所使用的修饰符都不1定要跟当前屏幕配置完全匹配,以便系统能够自己选择。具体来说,当基于尺寸修饰符选择资源的时候,如果没有更匹配的资源,系统会选择为比当前屏幕更小的屏幕所提供的资源(例如,在需要的时候large尺寸的屏幕可能会使用normal尺寸的资源)。另外,如果唯1能够使用的资源是为比当前装备屏幕更大的屏幕所提供的,那末系统将不会使用这些资源,并且利用程序会崩溃(例如,所有的layout资源都添加了xlarge修饰符,但是当前装备屏幕是normal尺寸屏幕)。更多关于系统选择资源的信息,请参考How Android Finds the Best-matching Resource.

小贴士: 如果你有1些图片资源希望系统永久不进行缩放(可能你想要在程序运行时由自己来控制和调剂),那末你应当把这些资源放到nodpi配置修饰符的资源文件夹中。在这个配置修饰符文件夹中的资源是密度无关的资源,系统永久不会对它们进行缩放。

3.2 设计可替换的布局和图片资源(Designing alternative layouts and drawables)

需要提供哪些可替换资源是根据你的利用程序需求来决定的。通常情况下,你需要使用尺寸和方向类的修饰符来提供可替换的layout资源,和使用密度类的修饰符提供可替换的图片资源。

下面章节将分别总结为何你要使用尺寸类或密度类修饰符提供可替换的layout资源或图片资源。

3.2.1 可替换布局资源(Alternative layouts)

通常情况下,只要你在不同配置的屏幕上测试你的利用程序,你就可以知道是不是需要为不同的屏幕尺寸提供可替换的layout资源了。例如:


  • 当你在small屏幕上测试的时候,你可能会发现你的layout不能很好的填充在屏幕上。例如,在small屏幕上,屏幕的宽度内不能填满多个按钮。这类情况下,你需要为small屏幕提供可替换的layout资源来调剂按钮的尺寸和位置。

  • 当你在extra-large屏幕上测试的时候,你可能会发现你的layout不能高效利用大屏幕的优势,并且全部布局都被拉伸来填满屏幕。这类情况下,你需要为extra-large屏幕提供可替换的layout资源,重新提供为大屏幕(例如平板)优化的UI。
    虽然你的利用程序不为大屏幕提供可替换layout资源也能够正常运行,但对用户来讲,提供可替换资源能让用户感觉这个利用程序就是为了他的装备所设计的。如果UI都被拉伸了,用户对利用程序的用户体验可能很反感。

  • 另外,当测试横向屏幕与竖向屏幕时,你可能会发现竖向屏幕底部的UI元素在横向屏幕上显示在屏幕右侧。


总结,你应当确认你的利用程序布局是存在以下几点:


  • 需要适配小屏幕(这样用户才能正常使用你的利用程序)
  • 是不是有对大屏幕进行优化以充分利用大屏幕带来的额外空间
  • 是不是有对横向和竖向屏幕进行优化


如果你的UI所使用的图片即便在被系统缩放layout以后也要填充全部view(例如按钮的背景图片),那末你应当使用Nine-Patch图片文件。Nine-Patch(点9图)文件实际上就是在png图片文件的基础上指定了两个维度上的可拉伸区域。当系统拉伸使用点9图的的view时,所使用的点9图也会被拉伸,只不过拉伸的只是点9图上指定的可拉伸区域。因此,如果使用点9图的话就不需要为不同的屏幕尺寸提供不同的图片,由于点9图能够自动调剂到任何尺寸。但是,你还是要为不同的屏幕密度提供可替换的点9图资源。

3.2.2 可替换图片资源(Alternative drawables)

几近每个利用程序都需要为不同的屏幕密度提供可替换的图片资源,由于每个利用程序都有1个启动图标,最少要保证这个启动图标在每块屏幕上都有良好的显示效果。一样,如果你的利用程序中还有其它的图片(例如菜单图标或其它图形),你都应当为不同的屏幕密度给每张图片都提供可替换的版本。

注意: 你只需要为图片文件(.png,.jpg或.git)和Nine-Patch文件提供密度相干的资源。如果你使用XML文件来定义图形、色彩或其它drawable resources,那末你只需要在默许的图片文件夹(drawable/)中保存1份代码就能够了。

要为不同的屏幕密度创建可替换的图片资源,你应当遵守6种通用屏幕密度图片的缩放比例3:4:6:8:12:16。例如,如果你有1张为medium屏幕密度设计的图片尺寸是48x48像素,那末其它尺寸应当为:


  • 36x36(0.75x),low屏幕密度
  • 48x48(1.0x 基准),medium屏幕密度
  • 72x72(1.5x),high屏幕密度
  • 96x96(2.0x),extra-high屏幕密度
  • 180x180(3.0x),extra-extra-high屏幕密度
  • 192x192(4.0x),extra-extra-extra-high屏幕密度(只需要启动图标,参考上面章节)


图4 每种屏幕密度之间图片的尺寸关系
屏幕密度之间图片尺寸关系

更多关于设计图标的信息,请参考Icon Design Guidelines。里面包括了各种图片资源的尺寸信息,包括启动图标、菜单图标,状态栏图标、标签图标等等。


为Android 3.2声明平板布局(Declaring Tablet Layouts for Android 3.2)




自从第1代运行Android 3.0系统的平板开始,为平板定义layout的重要方法就是把平板layout放到带xlarge配置修饰符的资源文件夹中(例如res/layout-xlarge)。为了兼容其它类型的平板和屏幕尺寸(特别是7英寸的平板),Android 3.2开始引入新的方法来为更碎片化的屏幕尺寸指定资源。相对尝试将你的layout适配到通用的尺寸(例如large或xlarge),新的技术是基于你的layout需要的空间大小(例如宽度要600dp)来调剂。

这么设计的缘由是当使用通用尺寸为7英寸平板做适配时,事情会变得非常辣手,由于7英寸平板在通用尺寸归类技术上与5英寸手机都划分为同1组(large类型)。虽然这类装备从尺寸上来看非常相近,但是对利用程序的UI占用的空间大小来讲是显著不同的,一样用户交互习惯也不同。因此,7英寸和5英寸屏幕不应当使用相同的layout资源。为了实现为这两种不同的屏幕尺寸提供不同的layout资源,Android现在允许你根据利用程序layout实际需要的尺寸来声明layout资源的类型,并且要使用dp单位。

例如,你在为平板装备特别设计好layout资源以后,应当在小于600dp宽度的屏幕上检查这些layout是不是能使用。由于使用这些平板layout资源的条件就是屏幕的最小尺寸是不是满足你声明的尺寸。因此,现在你可以为你的利用程序UI指定1些只有在可用宽度最少为600dp时才能使用的layout资源。

你应当在指定1个宽度的同时,以这个宽度作为最小尺寸来进行设计。否则,你需要在完成layout资源后测试你的layout能够支持的最小宽度。

注意: 所有使用新API指定的数值都是密度无关的值(dp),所以你的layout尺寸也应当使用dp单位来定义,由于你应当关心的只是系统计算屏幕密度后得出来的可用屏幕空间总值(强烈反对使用物理像素单位)。更多关于密度无关像素的内容,请参考上面术语与概念(Terms and concepts) 章节。

4.1 使用新的尺寸修饰符(Using new size qualifiers)

表2总结了能够根据屏幕可用空间大小来指定资源的配置修饰符。相比较于传统的通用屏幕尺寸类型(small、normal、large、xlarge),新的修饰符能基于你的利用程序支持的屏幕尺寸给你提供更多的控制。

注意: 你使用这些修饰符指定的尺寸不是实际上的屏幕尺寸。实际上,这些尺寸是你的Activity窗口可用宽度或高度的dp值。Android系统可能会占用1些屏幕空间来显示系统UI(例如屏幕底部的系统栏或顶部的状态栏),因此1些屏幕可能没法使用你的layout资源。也就是说,你声明的尺寸应当是你的Activity需要的尺寸――系统会统计系统UI占用的空间后决定给你的layout提供多大的空间。另外也要注意Action Bar也是你的利用程序组成部份,虽然你的layout资源没有声明它,但是它一样要占用你的layout可用空间的1部份,你在设计的时候也要把这部份给计算进去。

表2 新的屏幕尺寸配置修饰符(Android 3.2引入)

屏幕配置 修饰符 说明
最小宽度 (smallestWidth) swdp
例如:sw600dp、sw720dp
屏幕的基本尺寸,由屏幕可用区域的最短尺寸所决定。准确的说,装备的最小宽度就是屏幕最短的可用高度和宽度(你也能够认为是屏幕有可能显现的最短宽度)。你可使用这个修饰符来确保不管当前屏幕的方向如何,你的利用程序UI最少可用的宽度都有 dp。
例如,你的利用程序不管任什么时候候都要求屏幕宽度最少要600dp,那末你就能够使用这个修饰符创建1个layout资源并放到res/layout-sw600dp/的资源文件夹中。系统只会在当前屏幕可用最小尺寸为600dp时才会使用这个资源,并且不管这个600dp是用户认为的高度还是宽度。最小宽度是1个固定的屏幕尺寸,是屏幕的1个属性。不管当前屏幕的方向如何,装备的最小宽度都是不会变的。
装备的最小宽度要斟酌到屏幕的装潢空间和系统UI。例如,如果装备屏幕有1些持久性的UI沿着最小宽度的轴心占据1定的空间,那末系统声明的最小宽度值将会比实际屏幕的尺寸小,由于被占据的这部份屏幕空间你的UI永久没法使用。
这是相对传统通用尺寸修饰符(small、normal、large、xlarge)的替换方案,它允许你根据你的UI实际需要的可用尺寸定义离散的数值。使用最小宽度来定义通用尺寸是非常有用的,由于宽度通常是设计1个layout的关键因素。1个UI通常可以上下滑动,但是却在横向空间上没法扩大。可用宽度同时也是决定是不是在手机上显示单窗口layout或平板上显示多窗口layout的关键因素。因此,你应当更加关注每种装备上可能的最小宽度值是多少。
可用屏幕宽度 (Available screen width) wdp
例如:w720dp、w1024dp
通过值指定该资源文件夹中资源最小可用宽度的dp值。当屏幕在横向和竖向之间切换的时候,系统相应的宽度值会改变,以实时更新你的UI当前可用的实际宽度。
这通常对判断是不是使用多窗口layout非常有用,由于虽然是在平板装备上,你通常也不希望竖向多窗口布局与横向的相同。因此,你可使用这个修饰符来声明layout所需要的最小宽度,而不是同时使用屏幕尺寸和方向的修饰符来联合声明。
可用屏幕高度 (Available screen high) hdp
例如:h720dp、h1024dp
通过值指定该资源文件夹中资源最小可用高度的dp值。当屏幕在横向和竖向之间切换的时候,系统相应的高度值会改变,以实时更新你的UI当前可用的实际高度。
与使用wdp来定义layout所需宽度1样,使用hdp来定义你的layout所需要的高度也是非常有用的,它可以免使用屏幕尺寸和方向两种修饰符来进行组合定义。但是,大多数app不需要这个修饰符。由于UI在需要的时候1般都能够上下滑动,在可用高度的控制上本身就比较灵活,不像可用宽度没法扩大。


虽然看起来使用这些修饰符要比使用通用屏幕尺寸类修饰符更复杂,但是1旦你肯定了你的UI需求,使用这些修饰符实际上要简单很多。当你在设计UI的时候,你所关心的最主要问题应当是你的利用程序在手机风格的UI和平板风格的UI(使用多窗口)之间切换时,你所能使用的实际尺寸。这个UI风格切换的关键点取决于你特定的设计――可能你的平板layout需要720dp的宽度,也有可能600dp或480dp就够了,还有多是介于二者之间的某个值。使用表2中的修饰符,你就可以精确的控制你的layout切换临界值。

更多关于这些尺寸配置修饰符的资料,请参考Providing Resource文档。

4.2 配置实例(Configuration examples)

为了帮助你针对不同类型的装备进行设计,下面是1些典型屏幕宽度的数值:


  • 320dp:1种典型的手机屏幕(240x320 ldpi、320x480 mdpi、480x800 hdpi等等)
  • 480dp:像是平板装备的过渡线(480x800 mdpi)
  • 600dp:1种7英寸平板(600x1024 mdpi)
  • 720dp:1种10英寸平板(720x1028 mdpi、800x1280 mdpi等等)


使用表2中的尺寸修饰符,你的利用程序可以根据你想要的宽度(或高度)来设定准确的数值去促使手机和平板分别使用不同的layout资源。例如,如果600dp是你的平板layout能够支持的最小可用宽度值,你就能够提供下面两套layout资源:


res/layout/main_activity.xml           # 手机使用
res/layout-sw600dp/main_activity.xml   # 平板使用


在这个例子中,只有当前屏幕空间的最小可用宽度值为600dp时,你的平板layout才能够被使用。

如果你还想进1步自定义你的UI,例如分别为7英寸和10英寸平板设计不同的layout,那末你可以再补充额外的最小宽度值layout:


res/layout/main_activity.xml           # 手机使用 (小于600dp的可用宽度)
res/layout-sw600dp/main_activity.xml   # 7英寸平板使用(600dp或更大的屏幕宽度)
res/layout-sw720dp/main_activity.xml   # 10英寸平板使用(720dp或更大的屏幕宽度)


注意上面两个例子中的资源所使用的最小宽度修饰符swdp,它所指的是不管当前装备的方向怎样,屏幕宽高两条边中的最小宽度。因此,使用swdp从整体上疏忽了屏幕的方向并为你的layout指定屏幕的可用尺寸是1种比较方便的方法。

但是,在1些情况下,分辨当前可用宽度或高度对你的UI非常重要。例如,如果你有1个内置两个窗口的layout要显示两个边靠边的fragment,你可能就需要根据当前屏幕的宽度是不是大于等于600dp,和是不是横向还是竖向才能决定是不是使用这个layout。这类情况下,你的资源文件应当类似下面:


res/layout/main_activity.xml         # 手机使用(可用宽度小于600dp)
res/layout-w600dp/main_activity.xml  # 多窗口 (任何可用宽度大于等于600dp的屏幕)


注意第2套资源使用的可用宽度修饰符是wdp。使用这类方法,有些装备由于屏幕方向的改变致使两种layout都会使用到(例如屏幕在1个方向上可用宽度最少有600dp,而在另外一个方向可用宽度小于600dp)。

如果可用高度才是你需要关注的点的话,你一样也能够与上面1样使用hdp修饰符。乃至,你还可以联合wdphdp两种修饰符1块使用,如果你真的需要的话。。。

4.3 声明支持的屏幕尺寸(Declaring screen size support)

1旦你为不同的屏幕尺寸实现了对应的layout后,在你的manifest文件中声明你的利用程序所支持的屏幕也是一样重要的。

相对新的屏幕配置修饰符,Android 3.2也为manifest的 元素引入了新的属性。


  • android:requiresSmallesWidthDp
    声明支持的最小屏幕宽度。最小宽度指的是屏幕空间(dp单位)上最短的边能够给你的利用程序最小的可用宽度,换句话说就是在屏幕两条边上最短的可用边。因此,为了能让装备兼容你的利用程序,装备的最小宽度应当等于或大于声明的这个值。(通常声明的这个“最小宽度”值指的是你的layout所支持的值,并且不管当前屏幕是甚么方向。)
    例如,如果你的利用程序只支持最小可用宽度为600dp的平板装备:
<manifest ... > <supports-screens android:requiresSmallestWidthDp="600" /> ... manifest>


但是,如果你的利用程序支持Android所支持的所有屏幕(比如小到426dpx320dp),那末你可以不用声明这个属性,由于你的利用程序支持的最小宽度已覆盖了可能遇到的最小装备了。

慎重: Android系统其实不会注意这个属性,因此在运行的进程中这个属性其实不会对利用程序的行动产生任何影响。它的作用是在像Google Paly这样的服务中过滤你的利用程序。不过,Google Play当前其实不支持这个属性过滤(在Android 3.2版本上)。因此如果你的利用程序不支持小屏幕,你还需要继续使用其它关于尺寸的属性。


  • android:compatibleWidthLimitDp
    这个属性允许你通过指定你的利用程序所支持的最大的“最小宽度”值来启用屏幕兼容模式作为1个可选的功能。如果装备屏幕的最小边可用宽度值大于你声明的值,用户仍然能够安装你的利用程序,不过会在屏幕兼容模式下运行。默许情况下,屏幕兼容模式是关闭的,你的layout通常会被拉伸来填充屏幕。不过在系统栏会有1个按钮允许用户开启或关闭屏幕兼容模式。

    注意: 如果你的layout能够在大屏幕上正确的调剂大小,那末你不需要使用这个属性。我们建议你避免使用这个属性,你应当遵从本文档提到的其它方法来确保你的layout尺寸能够适配大屏幕。

  • android:largestWidthLimitDp
    这个属性允许你通过指定你的利用程序支持的最大的“最小宽度”值来强迫启用屏幕兼容模式。如果装备可用屏幕的最小边大于你声明的值,你的利用程序将会在屏幕兼容模式下运行,并且没有任何途径关闭兼容模式。

    注意: 如果你的利用程序layout能够在大屏幕上正确调剂大小,那末你不需要使用这个属性。我们建议你避免使用这个属性,你应当遵从本文档提到的其它方法来确保你的layout尺寸能够适配大屏幕。


慎重: 当为Android 3.2或更高版本系统开发利用程序时,你不应当使用旧的屏幕尺寸属性与上面列出的属性组合使用。同时组合使用新的属性和旧的尺寸属性可能会致使没法预感到到结果。

更多关于这些属性的信息,请参考上面列出的相干链接。


最好实践(Best Practices)




支持多样屏幕的目的是为了创建能够正常运行,并且在Android支持的通用屏幕装备上都能显示良好的利用程序。本文前面的章节论述了Android如何适配你的利用程序到不同的屏幕配置上,和你可以怎样为利用程序在不同的屏幕配置上定制不同的效果。本章节主要提供1些额外的小贴士,和关于确保你的利用程序在不同屏幕配置上都能良好缩放这类技术的概要。

下面是确保你的利用程序能够在不同屏幕上良好显示的快速检查列表:


  1. 在XML layout文件中指定尺寸时要使用wrap_content、fill_parent或dp单位。

  2. 不要在你的利用程序代码中使用固定的像素值。

  3. 不要使用AbsoluteLayout(已被废弃)

  4. 为不同的屏幕密度提供可替换的图片资源。


下面的章节提供更多的细节。

5.1 为layout的尺寸使用wrap_content、fill_content或dp单位

当在XML layout文件中定义view的android:layout_width和android:layout_height时,使用wrap_content、fill_parent或dp单位来确保view在当前装备屏幕上能够分配到1个适合的尺寸。

例如,1个view定义了layout_width="100dp",那末它在medium密度屏幕上将有100像素宽,而在high密度的屏幕上系统会将它放大到150像素宽,这样view就在屏幕上占据大约相等物理尺寸。

一样的,你应当使用sp(独立尺度像素)单位来定义字体的尺寸。sp的缩放因子由用户设定,系统会像处理dp1样缩放这些尺寸。

5.2 不要在利用程序的代码中写死像素值

出于性能缘由和为了保持代码的简单性,Android系统使用像素作为尺寸和坐标值的标准单位。这意味着1个view的尺寸在代码中都是用像素单位来表示,并且基于当前屏幕密度而变化。例如,如果myView.getWidth()返回值为10,这表示在当前屏幕上myView宽度为10像素,但是在更高密度的屏幕上,这个返回值可能为15像素。如果你在利用程序的代码中使用像素值来定义图片的尺寸,这会致使图片没法根据当前屏幕密度进行预缩放处理,你可能需要在自己的代码中自行缩放这些像素值来适配未经缩放的原图。

如果你的利用程序需要在运行时操作图片或处理像素值,请参考下面Additional Density Consideration章节。

5.3 不要使用AbsoluteLayout

不像其它的layout控件,AbsoluteLayout强迫使用固定的值来给子view布局,这样就致使在不同屏幕上很容易出现布局问题。因此,AbsoluteLayout在Android 1.5(API Level 3)就给废弃了。

你应当替换使用RelativeLayout,它能够根据相对位置给子view布局。例如,你可以指定1个按钮应当显示在1个TextView的右侧。

5.4 使用尺寸和密度相干的资源

虽然系统会根据当前屏幕配置自动缩放你的layout和图片资源,但你可能需要调剂UI在不同屏幕上的尺寸,和为不同的屏幕密度提供对应的图片资源。这实际上是重申上面章节讲的内容。

如果你需要控制你的利用程序在各个屏幕上的显示效果,你需要在特定资源文件夹中调剂你的layout和图片资源。例如,斟酌到1个图标需要在medium和high屏幕密度上显示,你可以简单的创建两个不同尺寸的图标(例如medium密度为100x100尺寸,high密度为150x150尺寸),然后分别将这个两个图标放到特定修饰符的资源文件夹中:


res/drawable-mdpi/icon.png   //for medium-density screens
res/drawable-hdpi/icon.png   //for high-density screens


注意: 如果1个资源文件夹的名字没有定义密度修饰符,那末系统会认为这个资源文件夹中的资源是为medium这个密度基准而设计的,并且在需要的情况下会为其它密度缩放这些资源。

更多关于有效配置修饰符的内容,请参考上面使用配置修饰符(Using configuration qualifiers)章节。


其它密度注意事项(Additional Density Considerations)




本章节将论述更多关于Android如何在不同屏幕密度上缩放图片资源,和如何更进1步控制图片在不同密度屏幕上的绘制。本章节的内容对大部份利用程序来讲不是那末重要,除非你的利用程序在不同屏幕密度上运行遇到问题,或你的利用程序需要操作图形。

为了更好的理解在运行进程中是如何操作图形来支持多种密度屏幕,你应当先理解系统用于确保正确缩放图片的途径:


  1. 预缩放资源(例如图片资源)
    基于当前屏幕的密度,系统使用你的利用程序提供的指定尺寸或密度修饰符的资源直接显示。如果提供的资源与当前屏幕密度不符合,系统将会加载默许的资源并放大或缩小这些资源来适配当前的屏幕密度。系统会假定默许的资源(就是那些保存在没有添加任何配置修饰符资源文件夹中的资源)是为屏幕密度的基准(mdpi)而设计的,除非系统加载的资源是从其它密度修饰符资源文件中加载的。所谓的预缩放就是系统将图片大小调剂到合适当前屏幕尺寸时做的处理。 如果你需要获得预缩放资源的尺寸,系统返回的将是缩放以后的资源尺寸。例如,1张为mdpi屏幕设计的图片为50x50像素,它将会在hdpi屏幕上放大到75x75像素(如果没有对应的hdpi资源替换的话),并且系统返回的尺寸也将是放大后的这个值。
    在1些情况下,你可能不希望Android系统进行预缩放资源处理。避免预缩放处理最简单的方法就是把资源放到nodpi配置修饰符的资源文件夹下。例如:
    res/drawable-nodpi/icon.png
    当系统从这个文件夹中获得icon.png资源时,系统会不根据当前装备密度对这张图片进行缩放。

  2. 自动缩放像素尺寸和位置
    利用程序可以通过在manifest文件中设置android:anyDensity属性为false,或在程序代码中把1张图片的Bitmap对象的inScaled属性设置为false来禁用预缩放处理。在这类情况下,系统将会在绘制进程中自动缩放绝对像素位置和像素尺寸。系统通过这么处理来保证使用像素定义的屏幕元素与在基准屏幕密度(mdpi)上显示的物理尺寸保持大致相同。系统所做的这些缩放处理对利用程序来讲是透明,利用程序获得到的也是缩放后的尺寸,而不是实际的物理像素尺寸。
    例如,假定1台装备是WVGA high密度的屏幕,它的分辨率为480x800并且与传统的HVGA屏幕的大小1样,现在它运行1个禁用预缩放处理的程序。在这类情况下,当利用程序要求屏幕尺寸时,系统将会“欺骗”利用程序,返回320x533尺寸(近似mdpi的屏幕密度)。以后,当利用程序履行绘画操作时,例如废除1个位于(10,10)到(100,100)的矩形,系统将会适当转换这个位置的值,实际上废除的区域为(15,15)到(150,150)。如果你的利用程序需要直接操作图片的缩放,这个误差可能会致使意想不到的结果,不过这是尽量斟酌利用程序的性能后得出的1个公道的方案。如果你遇到这类情况,请参考下面将dp单位转换为像素单位(Converting dp units to pixel units)
    通常情况下,你不应当禁用预缩放处理。支持多样屏幕的最好方法是遵从上面如何支持多屏幕(How to Support Multiple Screens) 章节提及的基本技术。


如果你的利用程序需要操作图片或需要通过其它方式在屏幕上直接与像素进行交互,那你可能需要采取额外的步骤来支持不同的屏幕密度。例如,如果你需要根据手指在屏幕上划过的像素点来辨认触摸手势并进行响应,你就需要采取适当的密度无关像素值来取代实际像素值。

6.1 缩放运行进程中创建的Bitmap对象(Scaling Bitmap objects created at runtime)

如果你的利用程序在内存中创建1张图片(1个Bitmap对象),默许情况下系统会假定这张图片是为medium这个基准屏幕密度而设计的,并且在渲染的时候会自动缩放。当Bitmap没有指定密度属性时,系统会添加“自动缩放”属性给Bitmap。如果你没有正确计算当前装备的屏幕密度并且为Bitmap对象指定相应的密度属性,自动缩放会跟你没有提供可替换资源的处理方法1样缩放这些Bitmap图片。

为了控制运行进程中创建的Bitmap对象是不是缩放,你可以通过Bitmap的setDensity()为其指定密度类型,该方法可选参数值为DisplayMetrics类中定义的常量,例如DENSITY_HIGH或DENSITY_LOW。

如果你是通过BitmapFactory从文件或数据流这些数据源创建了Bitmap对象,那末你可以当作这个Bitmap对象已存在1样,使用BitmapFactory.Options来设置bipmap对象的属性,系统通过这些属性来决定如何对它进行缩放。例如,你可以设置inDensity属性来设置bitmap对象对应的屏幕密度,和inScaled属性来

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐