SupportingMultiple Screens(支持多屏幕)

SupportingMultiple Screens(支持多屏幕)

安卓运行在不同尺寸和屏幕密度的设备上。对于程序来说,安卓系统提供统一的开发环境并且处理程序界面在屏幕上显示的大部分工作。

同时,为了优化在不同屏幕配置上的UI设计,系统也提供api允许你的程序给特定尺寸和密度的屏幕指定界面。例如,在平板和手机上你想要不同的界面。

虽然系统会为了你的程序适应不同屏幕缩放和改变大小,你也应该为不同屏幕尺寸和密度的设备优化你的程序。

这个时候,你在所有设备上都重视用户体验那么你的用户认为你的程序确实是为他们的设备设计的而不是简单的在他们的设备上进行伸缩。

按照下面文档里的练习,你可以用一个简单的apk文件创建一个程序并且在其支持的所有设备上很好的显示和提供一个优化的用户体验。

注意:文档中的信息假定你的程序是安卓1.6或更高版本,如果你的程序支持安卓1.5或者更低,请先阅读Strategies for Android 1.5.同样,请注意从安卓3.2开始引入了一些新的api允许你更精确的控制给不同尺寸的屏幕提供的布局资源。如果你正在给运行在平板上的程序做优化这些新的特性尤其重要。更多详情,请看Declaring Tablet Layouts for Android 3.2.部分。

屏幕支持概述

这一部分提供安卓支持不同屏幕的概述,包括:在文档和api中术语和概念的介绍,系统提供的屏幕配置的摘要,api概述和向下的屏幕兼容特性。

术语和概念

屏幕尺寸:实际的物理大小,通过屏幕对角线测量。为了简化,安卓把所有的屏幕尺寸归类为四种尺寸:small,normal,large和extra-large。

屏幕密度:屏幕上一个物理区域像素的数量;通常dpi(每英寸有多少像素点),例如,“low”密度的屏幕在单位物理区域上的像素比“normal”和“high”更少。

为了简化,安卓将屏幕密度归类为六种密度:low, medium, high, extra-high, extra-extra-high, 和extra-extra-extra-high

向:用户使用view时屏幕的方向。横向或者是纵向,意思就是说屏幕的方向比例是更宽还是更高。

Be aware that not only do different devices operate in different orientations by default,当用户旋转设备时设备的方向会变化。

分辨率:一个屏幕上所有物理像素的总数。当增加对多种屏幕的支持时,程序不会直接对分辨率起作用;程序应该只关心所处归类分组的尺寸和密度

密度-独立像素(Density-independentpixel (dp))

        虚拟的像素单位,定义用户界面布局时使用,用密度独立的方法表示布局大小或者位置。

        密度独立像素和160dpi屏幕上一个物理像素是相同的,160dpi的密度是基线密度也就是系统假定的“medium”的屏幕密度。

        在运行时,基于使用中实际的屏幕密度系统会控制dp单位的缩放。dp单位和屏幕密度的转换非常简单:px=dp*(dpi/160)即:px/dp=dpi/160

        例如:在一个240dpi的屏幕上,1dp等于1.5物理像素。为了确保在不同密度的屏幕上适当的展现你的用户界面,当你定义用户界面时应该使用dp单位。

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

从安卓1.6开始,考虑到设备可能有许多不同的屏幕配置,安卓提供多屏幕尺寸和密度支持。

        你可以利用安卓系统的特性来给不同屏幕配置进行界面优化,保证你的程序不仅仅只是显示出来而是在不同屏幕上提供最好的用户体验。

        为了简化给不同屏幕设计界面,安卓将实际的尺寸和密度分为:

        四组尺寸分类:small, normal,large, and xlarge

        注意:从安卓3.2开始,这个尺寸分类被新的基于可以屏幕宽度的屏幕管理技术取代。

        如果你开发的app是3.2或者更高,参看Declaring Tablet Layouts forAndroid 3.2

        六组密度分类:

        ldpi (low) ~120dpi

        mdpi (medium)~160dpi

        hdpi (high) ~240dpi

        xhdpi (extra-high)~320dpi

        xxhdpi(extra-extra-high) ~480dpi

        xxxhdpi(extra-extra-extra-high) ~640dpi

尺寸和密度的分类都是基于normal大小和mdpi密度而演化而来的。normal大小和mdpi密度的配置是第一台安卓手机的配置-T-Mobile G1。

T-Mobile G1有一个HVGA的屏幕(直到安卓1.6,这是安卓唯一支持的屏幕)

每个尺寸和密度的分类都表示一个范围的屏幕尺寸和密度,例如,两个设备都有normal的屏幕尺寸但是手动测量他们实际的屏幕尺寸和方向比例还是会有轻微的不同。

同样两个都是hdpi密度的屏幕实际测量的像素也可能有轻微差别。安卓给程序做出区分,你就可以给不同分类设计用户界面最终让系统来进行适配。

图1表示了不同的尺寸和屏幕密度是如何被安卓粗略分成不同类的尺寸和密度的。


就像你给不同屏幕设计UI,每个设计都有一个最小空间的要求。上面每个屏幕尺寸的分类都有一个系统规定的最小分辨率。这个最小尺寸是用dp做单位

和你定义布局使用的单位相同,这样就不用担心屏幕密度的变化。

xlarge screens are at least960dp x 720dp

large screens are at least640dp x 480dp

normal screens are at least470dp x 320dp

small screens are at least426dp x 320dp

注意:这些最小屏幕尺寸在安卓3.0之前是没有定义的,所以你可能遇到一些处于normal和large之间的设备是错误的分类。

这个通常基于屏幕的物理分辨率,因此可以跨越设备。例如一个1024*720的平板上面有系统栏(system bar)由于使用系统栏所以用于程序的空间就会少一点。

为了给不同屏幕尺寸和密度优化程序UI,你可以给尺寸和密度分类提供可选资源。针对有代表性的屏幕,你可以提供可选的布局给不同屏幕尺寸,

可选的bitmap图像给不同的分辨率。在运行时,系统会基于当前屏幕所在的尺寸和密度分类为应用选择合适的资源。

你不需要为每一个屏幕尺寸和密度组合提供可选资源。系统提供了强大的兼容特性在绝大多数屏幕上都可以处理你的应用的展示

提供运用调整大小技术所设计的UI(就像下面Best Practice描述的)

注意:概括一个设备的屏幕尺寸和密度特征要和其他进行区分。

例如,一个WVGA high-density屏幕被认为是一个normal尺寸因为它的物理尺寸和T-Mobile G1(安卓第一部手机也是屏幕的基线配置)相同。

另一方面,一个WVGA  medium-density屏幕被看作是一个large尺寸的屏幕。虽然提供相同的分辨率(相同数量的像素),WVGA  medium-density

有更低的屏幕密度,意味着每个像素会更大,所以屏幕大小要比基线屏幕(normalsize)大。

密度独立

        Your application achieves"density independence" when it preserves the physical size

        (from the user's point of view) ofuser interface elements when displayed on screens with different densities.

维护密度独立是很重要的,否则一个界面元素(例如一个button)在低密度屏幕上很大在高密度屏幕就会很小。如果这样在你应用的布局和可用性上都会出现问题。

图2和图3分别展示了提供密度独立和不提供密度独立的情况

安卓系统可以在两方面帮助你的应用实现密度独立:

1、针对当前屏幕密度系统对dp单位进行缩放

2、如果有必要,系统会基于当前屏幕密度对drawable资源进行缩放

在图2中,TextView和bitmap drawable是用px单位定义的,所以view在低密度屏幕大高密度屏幕小。即使屏幕尺寸相同高密度屏幕会有更多的像素点在单位面积上。

在图3中,布局大小用dp指定。因为基线密度-独立像素是medium-density屏幕,所以在具有medium-density密度的屏幕上看起来和图2中medium-density屏幕是一样的。

对于不同密度的屏幕,系统会缩放密度独立像素的值,来适配屏幕。

大多数情况,你可以根据情况简单的指定所有布局的大小用dp或者“wrap_content”来保证密度独立。

系统会根据当前屏幕密度适当的缩放bitmap drawable来做展示。

不管怎样,bitmap缩放会是bitmap变得模糊,你也许在上面的截图中注意到了。为了避免,你应该给不同的密度提供不同的bitmap资源。

例如,给高密度屏幕提供高分辨率bitmap,系统将会使用这些而不是将medium-density进行缩放。下面的部分介绍更多的如何给不同屏幕密度提供可选资源。

如何支持多种屏幕

对于不同程序不同屏幕配置选择适当的布局和bitmap drawable是安卓支持多屏幕的基础能力。

系统处理大多数工作使程序合适的展现在不同的屏幕配置上通过缩放布局来适配屏幕尺寸/密度,缩放bitmap drawable来适应屏幕密度。

要更优雅的处理不同屏幕配置,你应该:

*在配置文件中明确声明你的应用支持的屏幕尺寸

声明你的应用支持哪些屏幕尺寸,确保你唯一支持屏幕的设备可以下载你的程序。声明支持不同的屏幕尺寸同样可以影响系统如何在大屏幕上绘制你的程序,

不管你的程序是否是在屏幕兼容模式下运行。

声明你的应用的屏幕支持尺寸,你可以在配置文件<supports-screens>中指定

*给不同屏幕提供不同布局

默认情况下,安卓会根据当前设备屏幕调整程序。大多数情况都没问题。少数情况你的用户界面看起来不够好并且需要为屏幕调整界面。

例如,在一个大的屏幕上,你可能像调整一些元素的位置和尺寸来利用额外的空间,或者在一个小屏幕上,你也可能要调整尺寸让内容都可以显示出来。

你可以用来进行尺寸限定的的资源是 small,normal,large和xlarge。例如,给超大屏幕用的布局应该放在 layuout-xlarge/

从安卓3.2开始,上面的尺寸集合被不再被推荐使用,你应该使用sw<N>dp表示你布局资源的最小可用宽度。

例如,如果你的多窗口平板布局需要至少600dp的屏幕宽度,你应该把它放在layout-600dp/下。

关于使用这项新技术声明布局资源进一步的讨论参照Declaring Tablet Layouts for Android 3.2.

*给不同屏幕密度提供不同的bitmap drawable

默认情况下,安卓缩放bitmapdrawables(.png, .jpg, and .gif 文件)和Nine-Patch drawables (.9.png 文件)以便于在每种物理尺寸的设备上展现出来。

例如,如果你的程序置为基线设备提供bitmapdrawable,medium 屏幕密度(mdpi),系统将在一个高密度屏幕上对他们进行放大,在一个低密度屏幕设备上缩小。

This scaling can causeartifacts in the bitmaps。确保bitmap能很好的展现,你应该给不同分辨率屏幕提供不同解决方案。

配置分类(下面将详细介绍)你可以用来指定屏幕密度的有

ldpi (low), mdpi (medium),hdpi (high), xhdpi extra-high), xxhdpi (extra-extra-high), and xxxhdpi(extra-extra-extra-high)

例如,给高密度屏幕使用的bitmap应该放在drawable-hdpi/下。

注意:mipmap-xxxhdpi限定词是仅仅需要提供一个应用图标,比在一般xxhdpi设备上会更大。不需要给应用所有图像提供xxxhdpi资源

一些设备会放大应用图标差不多25%。例如,如果你最高密度应用图标图像是extra-extra-high-density。

the scaling process willmake it appear less crisp压缩过程将会

你应该在mipmap-xxxhdpi目录提供一个更高密度的应用图标,系统就避免将一个小的图标放大。

更多信息参看Provide anxxx-high-density launcher icon。除了应用图标其他用户界面你不能使用xxxhdpi限制符

注意:将所有应用图标放在res/mipmap-[density]/文件夹下而不是res/drawable-[density]/下。安卓在密度指定的文件夹下保持资源,

                  比如mipmap-xxxhdpi,不管安装在什么样分辨率的屏幕上。这个设计允许桌面程序选取最佳分辨率的图标在主页面显示。

                  跟多信息参看Managing Projects Overview.

尺寸和密度的配置限制符和上面的Rangeof screens supported是一致的

注意:如果你不熟悉配置限定符和系统如何用可选资源,请阅读 Providing Alternative Resources获得更多信息

运行时,系统会根据提供的资源按照下面步骤达到最好的展现:

1、系统使用合适的可选资源

             基于当前屏幕的尺寸和密度,系统使用你的程序提供的尺寸和密度指定的资源。例如,如果设备是高密度屏程序需要一个drawable资源,

             系统会查找和设备配置最佳匹配的drawable资源文件目录。根据其他可用的可变资源,如果hdpi资源目录(比如drawable-hdpi/)有可能是最佳匹配的,

             系统就会使用这个文件夹下的资源。

2、如果没有匹配的资源可用,系统使用默认的资源并且进行缩放来匹配当前屏幕

             默认资源是没有配置限定标记的。例如,在drawable/下的资源就是默认的资源。系统假定默认资源是按照基线设备(normal屏幕,medium密度)尺寸和密度设计的,。

             同样系统会在高密度屏幕和低密度屏幕上对默认密度资源进行适当的放大和缩小。

             无论如何,当系统在密度指定文件夹下没有找到密度指定资源,系统不会每次都使用默认资源。为了有更好的缩放效果系统可能会使用另一个密度指定的文件夹资源。

             例如,当我们要寻找的low-密度资源不可用,系统跟倾向于将high密度的资源进行缩放,因为系统将一个high密度的资源缩小到0.5比将一个medium密度资源缩小到0.75更容易。

     更多关于安卓如何选择可选资源来匹配设备配置的配置限定请阅读How AndroidFinds the Best-matching Resource.

使用配置限定符

              安卓支持多个配置限定符,允许你自己根据当前屏幕特征控制系统如何选择可选资源。

              配置限定符是一个你可以添加到你安卓应用目录并且给在目录中设计好的文件指定配置的字符串。

              使用配置限定符:

              1、在res/文件夹下创建目录并且按照以下格式命名:

              <resources_name>-<qualifier>

              <resources_name>是标准的资源名称(比如drawable或者layout)

              <qualifier>是下面表格1中的配置限定符,给使用的资源(比如hdpi或者xlarge)指定指定屏幕配置

              可以使用多个限定符中间用-隔开

              2、在新的目录保存合适的配置指定资源。资源文件命名必须和默认资源文件结构相同。

              例如,xlarge是extra-large屏幕的配置限定符。当你把限定符加到资源目录名称后(比如layout-xlarge),这样就告知系统这些资源是用在有extra-large屏幕的设备上的。

              表1。配置限定符允许你给不同屏幕配置提供不同资源。




注意:如果你的程序运行在安卓3.2或者更高,参看Declaring Tablet Layouts for Android 3.2获取更多关于新的配置限定符用于指定不同屏幕尺寸的布局资源。(替代表1中的尺寸限定符)

更多关于这些限定符是指的屏幕尺寸和密度的粗略范围,参见Range of Screens Supported在文档的前面。

例如,下面的程序资源目录给不同屏幕尺寸和不同的drawable提供不同的布局设计。mipmap/文件夹用来放应用图标。

res/layout/my_layout.xml              //正常屏幕尺寸布局 (默认)
res/layout-large/my_layout.xml        //大屏幕尺寸布局
res/layout-xlarge/my_layout.xml      // X大屏幕尺寸布局
res/layout-xlarge-land/my_layout.xml  //横向X大屏幕尺寸布局


res/drawable-mdpi/graphic.png        //正常密度bitmap
res/drawable-hdpi/graphic.png        //高密度bitmap
res/drawable-xhdpi/graphic.png        // X高密度bitmap
res/drawable-xxhdpi/graphic.png      // XX高密度bitmap

res/mipmap-mdpi/my_icon.png        //正常密度应用图标
res/mipmap-hdpi/my_icon.png        //高密度应用图标
res/mipmap-xhdpi/my_icon.png        // X高密度应用图标
res/mipmap-xxhdpi/my_icon.png      // XX高密度应用图标
res/mipmap-xxxhdpi/my_icon.png      // XXX高密度应用图标

更多信息关于如何使用可选资源和配置限定符的完整列表(不仅仅包括屏幕配置)参看Providing Alternative Resources.

意识到,当安卓系统运行时选择资源时,它用一些逻辑来确定最佳资源。That is, the qualifiers you use don't have to exactly match the currentscreen configuration in all cases in order for the system to use them. (你使用的限制符没必要为了给系统使用而把当前屏幕配置的所有分类限定符都写出来)。

特别是,当基于尺寸限定符选择资源时,如果没有和当前屏幕匹配的系统会选择比当前屏幕小的资源(例如,如果有必要large-size屏幕使用normal-size屏幕资源)。然而,当唯一可用资源比当前屏幕大,程序不会使用这些资源,如果没有其他和屏幕配置匹配的资源程序将会崩溃(例如,如果所有布局资源都被xlarge限定符标记,但是设备是normal-size 屏幕)。更多关于系统如何选择资源的信息,请阅读How Android Finds the Best-matching Resource.

提示:如果你有一些系统不能缩放的drawable资源(获取你在程序运行是对图片进行了调整),你应该把他们放到nodpi配置限定符文件夹下。这个文件夹下的资源被认为是密度不可知的系统不会缩放他们。

设计可选布局和drawable

       根据程序需要你应该提供各种类型的可选资源。通常,你应该使用尺寸和方向限定符来提供可选布局资源,密度限定符来提供可选bitmap drawable资源。

下面的部分总结如何分别使用尺寸和密度限定符来提供可选布局和drawables。

可选布局

通常,当你在不同设备配置上测试你的程序时你会知道你是否需要不同屏幕尺寸的可选布局。例如:

*当在小屏幕上测试,你可能会发现你的布局不能很好的适配屏幕。例如,在一个小屏设备上一行的button可能放不下。在这个例子中你应该给小屏幕提供可选布局来给button提供合适的尺寸和位置。

*当在xlarge尺寸屏幕测试时,你应该认识到你的布局是明显拉伸来适配大屏幕的。在这个例子中你因该给xlarge屏幕提供可选布局,提供一个给大屏比如平板重新设计的UI。

虽然你不提供可选布局给大屏你的程序也不会出现问题。但你的程序看起来是给他们设备专门做的对于用户来说是非常重要的。如果UI明显看起来是被拉伸的用户可能会对程序产生不满。

*如果在横竖屏上进行对比测试,你应该注意在竖屏上底部的按钮应该在横屏上放在右边。

总结,你因该确认你的布局:

*适配小屏幕(用户实际上可以使用你的应用)

*针对大屏幕优化,利用增加的屏幕空间

*优化横竖屏

如果你的UI使用bitmap来适配一个view甚至是系统缩放后(像一个button的背景图片),你应该使用nine-patch bitmap文件。nine-patch文件是基于png文件,你需要在nine-patch文件中指定两个拉伸的区域。当系统想缩放使用了bitmap的view时,系统拉伸nine-patch图片,仅仅拉伸指定的区域。像这样就不用给不同屏幕尺寸提供不同的drawable,因为nine-patch可以调整到任何尺寸。你应该给不同屏幕密度提供不同的nine-patch文件。

可选drawable

几乎每个程序都给不同屏幕密度设备提供可选drawable资源,因为几乎每个程序都有应用图标并且图标应该在所有屏幕分斌率下都显示良好。同样的,如果你的程序中有其他的bitmap drawable(比如菜单的图标或者其他图形),你应该给不同分辨率提供可选的版本或者每个分辨率都提供一个。

注意:你只需要提供密度指定的drawable,bitmap(.png.jpg, or .gif)或者nine-patch(.9.png

如果使用xml文件来定义sharpe,colors或者其他drawable资源,你应该放一个默认的副本在默认drawable文件夹下(drawable/)。

为不同密度创建可选bitmap drawable,在六个常用的密度中你应该遵守3:4:6:8:12:16缩放比率。

例如,如果你有一个48像素*48像素的bitmapdrawable提供给medium密度屏幕,所有其他尺寸应该是:


·  36x36 (0.75x) for low-密度

·  48x48 (1.0x baseline) for medium-密度

·  72x72 (1.5x) for high-密度

·  96x96 (2.0x) for extra-high-密度

·  180x180 (3.0x) forextra-extra-high-密度

·  192x192 (4.0x)for extra-extra-extra-high-密度 (只用于图标; 看上面的提示)

更多关于设计图标的信息,参看 Icon Design Guidelines,其中包含各种bitmap drawable的尺寸信息,像应用图标,菜单图标,状态栏图标,标签图标等等。

给安卓3.2声明平板布局

第一代平板运行安卓3.0,声明平板布局应该将他们放在xlarge的限制符文件夹下,(例如,res/layout-xlarge/)。为了适应其他类型的平板尤其是屏幕尺寸,7寸平板-安卓3.2为分散的屏幕尺寸引入了一个新的指定资源的方式。这种新技术基于布局需要的空间总数(例如宽度600dp)而不是让布局来填充分类的尺寸(例如large或xlarge)。

给7寸平板设计设计的原因是7寸平板和5寸手机在之前的分类中属于同一类(large分类)。这两个设备看起来尺寸接近,但是给程序提供的空间是不同的,as isthe style of user interaction(是用户交互的样式)。这样 7寸和5寸不应该用同样的。安卓现在允许你基于以dp为单位的宽度或者高度来给你的应用指定不同布局资源这样就可以给这两个种类屏幕提供不同布局。

例如,当你给平板样式的设备设计完布局后,你可能觉得这个布局这个布局在宽度小于600dp设备上不会很好的显示。这个成为了给你的平板布局提供的最小值。同样的,你可以指定你程序UI的布局资源应该使用在宽度至少600dp的屏幕。你可以选一个宽度作为你的最小宽度来设计或者测试你的布局支持的最小宽度。

注意:所有的使用了新尺寸的APIs都是密度独立像素(dp)值你布局的尺寸也应该定义成dp单位,because what you care aboutis the amount of screen space available after the system accounts for screendensity (as opposed to using raw pixel resolution) 因为你应该关心的是屏幕可用空间总量而不是占屏幕密度的比例(和使用像素密度相反)

使用新的尺寸限定符

根据可用屏幕空间给布局指定不同的资源配置如表2所述。新的限定符比起指定支持的屏幕尺寸能让你更多的控制,相比较传统的屏幕空间(small, normal, large, 和 xlarge)

注意:你使用限定符指定的尺寸不是真的屏幕尺寸。而是Activity所在窗口的可用dp单位。安卓系统会将一部分屏幕空间来显示UI(例如顶部的状态条和底部的系统条),有一些屏幕空间不是给布局使用的。这样你声明的尺寸指的是Activity需要的大小,当给布局声明空间是系统会给系统UI留出一部分空间。Actionbar是程序界面空间的一部分,虽然你的布局不需要声明,所以他会减少屏幕可用空间设计界面时应留出空间。

表2屏幕尺寸的配置限定符(安卓3.2引入)

 




更多关于尺寸限定符的讨论,参见Providing Resources文档。使用这些限定符可能比使用屏幕分类更加困难,一旦你决定了你的需求这种方式是很简单的。当你设计你的UI,你主要关心的事情是确切的尺寸你的应用在手机模式和平板多窗口模式做出选择。选择的准确点取决于独特的设计或许你需要给你平板布局720dp的宽度,或许600dp就够了或许480dp,或者这些中间的一些。使用表2中的限定符,你的布局改变时你能准确掌控尺寸。

配置举例

帮助你给不同设备设计,这儿有一些典型的屏幕宽度:

*320dp:一个典型的手机屏幕(240x320ldpi, 320x480 mdpi, 480x800 hdpi等)

*480dp:atweener tablet like the Streak (480x800 mdpi)

*600dp:7寸平板(600*1012 mdpi)

*720dp:10寸平板(720x1280 mdpi, 800x1280 mdpi等)

使用表2中的尺寸限定符,程序能从手机和平板的不同布局资源中进行选择无论布局高度和宽度。例如,如果600dp是你的平板布局支持的最小可用宽度,你可以提供两个布局的集合:

res/layout/main_activity.xml          # For handsets
res/layout-sw600dp/main_activity.xml  # For tablets

在这个例子中,可用屏幕空间最小宽度一定是600dp为了让平板布局能够应用。

其他的例子中你想在7寸和10寸平板上都深度定制UI,你可以增加最小宽度布局:

res/layout/main_activity.xml          # For handsets (smaller than 600dpavailable width)
res/layout-sw600dp/main_activity.xml  # For 7” tablets (600dp wide and bigger)
res/layout-sw720dp/main_activity.xml  # For 10” tablets (720dp wide and bigger)

注意前面两个资源集合使用了“smallest width”限定符,sw<N>dp,指定了屏幕两边中最小的一边,不管屏幕当前的方向。这样,使用sw<N>是一个忽略屏幕方向为布局指定屏幕全部可用尺寸简单的方法。

然而,在一些例子中,对于你的布局重要的是确定当前可用的宽和高。例如,如果你有两个fragment并排的两个窗口布局,你可能在屏幕最小宽度是600dp时使用这个布局,不管设备是横屏还是竖屏。在这个例子中,你的资源可能是这样的:

res/layout/main_activity.xml        # For handsets (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # Multi-pane (any screen with 600dpavailable width or more)

注意第二个集合使用了“available width”限定符,w<N>dp,这种方式,一个设备可以精确使用两种布局,取决于屏幕方向(如果在一个方向上可用宽度最小是600dp而另外一个方向小于600dp)。

如果可用高度也是你关心的,你可以类似的使用h<N>dp限定符。或者,结合w<N>dp 和 h<N>dp以如果需要非常具体的指定。

声明屏幕尺寸支持

一旦你给不同屏幕尺寸实现了布局,在配置文件中声明你要支持的屏幕是同样重要的。

随着新的屏幕尺寸限定符,安卓3.2给配置元素<supports-screens>引入了新的属性:

android:requiresSmallestWidthDp

指定了需要的最小宽度。最小宽度是屏幕空间的最短尺寸(dp单位)并且对你的程序UI是可用的,可用屏幕空间两边中最短的。为了让一个设备被认为兼容你的程序,设备的最小宽度必须相等或者大于这个值。(通常,你提供的你布局所支持的最小宽度,不管屏幕当前方向)

例如,如果你的程序仅仅给最小可用宽度为600dp的平板设备使用:

<manifest ...>
    <supports-screens android:requiresSmallestWidthDp="600"/>
    ...
</manifest>

不管怎样,如果你的程序支持安卓支持的所有屏幕尺寸(像426dp*320dp一样小),你不需要声明这些属性,因为你程序需要的最小宽度在任何设备上都是最小的。

警告:安卓系统不会重视这些属性,所以他不会影响你的程序运行时的行为。反而,他用来给你的程序过滤设备例如谷歌商店。然而,谷歌商店当前不支持这个属性来过滤(在安卓3.2),所以如果你的应用不支持小屏幕,你应该继续使用其他尺寸属性。

android:compatibleWidthLimitDp

这个属性允许你开启屏幕兼容模式作为一个用户可选属性用来指定你的程序支持的最大的“最小宽度”。如果设备可用屏幕的最短边你的值还要大,用户也可以安装程序,但是会在屏幕兼容模式运行。默认情况下,屏幕兼容模式是关闭的你的布局要调整大小来适应屏幕,但是系统条上的一个按钮变成可用,允许用户开启或关闭屏幕兼容模式。

注意:如果你的程序布局可以在大屏幕上很好的调整大小,你不需要使用这个属性。我们建议你不要使用这个属性而是按照文档中的建议确保你的布局可以在大屏幕上很好的展示。

android:largestWidthLimitDp

这个属性允许你强制开启screen compatibility mode 指定     你的程序支持的 “最小宽度”的最大值。如果设备可用屏幕的最小边比你的值还大,程序运行在屏幕兼容模式,用户不可关闭。

注意:如果你的程序能在大屏幕上合适调整大小,你不需要使用这些属性。我们建议你避免使用这个属性而是确保按照文档里的建议你的布局能在大屏幕上调整大小。

警告:当开发安卓3.2和更高的版本,你不用把老的屏幕尺寸属性和上面列表的属性混合使用,新旧属性混合使用可能会导致不明情况。

关于这些属性中每个的更多信息,在各自链接中查看。

最好的练习

支持多屏幕的目标就是创建的应用能正确运行并且在安卓支持的所有屏幕上都可以适配。文档前面的部分提供关于安卓如何让你的应用适应屏幕和如何在不同屏幕上定制界面。前面部分的一些提示和技术概要可以确保你的应用在不同屏幕上合理的缩放。

这有一个关于怎样确保你的应用在不同屏幕上合理展示的快速预览清单:

1、使用wrap_contentfill_parent或者dp单位当在xml文件中指定大小时

2、在程序代码中不要使用px硬编码

3、不要使用绝对布局(已经废弃)

4、给不同屏幕密度提供可选bitmapdrawables

下面的部分将详细介绍

1、使用wrap_contentfill_parent或者dp单位给布局尺寸

当给xml文件中的view中定义android:layout_width 和 android:layout_height时,使用wrap_contentfill_parent或者dp单位可以保证view在当前设备屏幕上有合适的尺寸。

例如,一个view使用layout_width="100dp"那么它的宽度中密度屏幕上是100px在高密度屏幕上就是150px,view会在屏幕上占据相近的物理空间。

类似的,你应该用sp(scale-independent pixel)来定义字体大小。sp的缩放比例根据用户的设置和系统的缩放类似dp

2、在程序代码中不要使用px硬编码

为了展示和保持代码简洁,安卓系统使用像素作为标准单位用来表示尺寸和坐标值。这意味着一个view通常基于当前屏幕密度的尺寸在代码中用像素表示。例如,如果myView.getWith()返回10,这个view在当前屏幕上是10像素宽,但是如果在高密度的屏幕上可能就是15。如果你在程序中用像素值对bitmap编码,并且没有针对当前屏幕进行预先缩放,你要对未缩放的bitmap资源通过缩放后的像素再定义。

如果你的程序操作bitmap或者运行时用像素值来定义,请参看下面部分Additional Density Considerations.

3、不要使用绝对布局

和其他布局不同,绝对布局强制在子view上使用固定的位置,

附加密度

这节将更多的描述安卓如何在不同屏幕分辨率上缩放bitmap drawable和进一步控制bitmap在不同密度上的绘制。本节中的内容对于大部分程序来说不太重要,除非你的程序在不同屏幕密度设备上运行时遇到问题或者当你的程序处理图像时。

为了更好的理解运行时如何操纵图像来支持多种密度的屏幕,你应该明白系统会帮助确认bitmap合适的缩放比例通过下面方法:

1、提前缩放资源(像bitmapdrawables)

基于当前屏幕的密度,系统从你的程序使用任何一个尺寸或者密度指定的资源无缩放的展示他们。如果资源对于正确的密度是无效的,系统加载默认的资源并进行缩放来匹配当前屏幕密度。系统假设默认资源(没有配置限定符的目录)是给基线屏幕密度设计的,除非从一个密度指定的资源目录。提前缩放是这样的,调整bitmap到合适的尺寸来适应当前屏幕密度。

如果你要获取提前缩放资源的大小,返回值是缩放后的值。例如一个bitmap设计成50*50像素提供给mdpi屏幕在hdpi屏幕上缩放成75*75像素(如果没有提供给hdpi的可选资源)系统同样的记录这个尺寸。

有一些情况你可能不想让安卓预先缩放资源。不让系统缩放资源简单的方法是将资源文件放在nodpi配置限定符的资源文件夹。例如:

res/drawable-nodpi/icon.png

当系统使用这个目录下的icon.png,在当前屏幕密度上不会缩放。

2、自动缩放大小和坐标的像素

程序可以通过在配置文件中设置android:anyDensity为 "false"或者以变成方式设置bitmap的inScaled 为 "false"

在这个例子中,系统自动缩放任何一个绝对像素坐标和坐标大小值在绘制时。这样做为了确定用像素表示的屏幕元素仍然展示和基线屏幕密度(mdpi)近似的物理大小。The system handles thisscaling transparently to the application and reports the scaled pixeldimensions to the application, rather than physical pixel dimensions.系统掌握程序明显缩放且记录程序缩放的像素大小,而不是物理尺寸大小。

例如,假设一个设备有一个WVGA的高密度屏幕,480*800和一个惯例的HVGA屏幕有一样的尺寸,它上面运行的程序关闭了提前缩放。在这个例子中,当查询屏幕大小时系统将会对程序撒谎,报告是320*533(屏幕的密度将被转化为近似mdpi)。然后,当程序在做绘制(draw)操作时,例如让从(10.10)到(100.100)的矩形无效,通过缩放他们合适的数量来转换坐标,实际使无效区域是从(15.15)到(150.150)。这个差距可能出现超出预料的显示如果程序直接操纵缩放的bitmap,但这被认为是保持程序很好展现的一个合理的交易。如果你遇到这个情况,阅读下面部分的Converting dp units to pixel units.

通常,你不要关闭提前缩放。支持多屏幕最好的方式遵守基础技术描述在上文的How to Support Multiple Screens.        

如果你的程序操作bitmaps或者在一些其他方法上直接和屏幕上的像素交互,你可能需要有附加的步骤来支持不同的屏幕密度。例如,如果你通过手指划过的像素数量来响应手势,你需要使用密度-独立像素值来替代使用实际的像素。

缩放运行时产生的Bitmap对象

如果你的程序创建一个在内存中的bitmap(一个Bitmap对象),系统会假定是给基线medium-density屏幕设计的,默认情况下,绘制时会自动缩放bitmap。系统给一个Bitmap声明auto-scaling当bitmap没有指定密度属性。如何你没有正确的解释当前设备屏幕密度和指定bitmap的密度属性,auto-scaling可以导致scalingartifacts和你不提供可选资源一样。

来控制运行时创建的Bitmap是否缩放,你可以指定Bitmap的密度用setDensity(),通过DisplayMetrics可以获得一个密度常量,像DENSITY_HIGH或者DENSITY_LOW

如果你使用BitmapFactory创建Bitmap,像从一个文件或者从一个流你可以使用BitmapFactory.Options定义Bitmap的内容就像它已经存在一样,这将决定系统是否缩放或者怎样缩放他们。例如,你可以使用inDensity属性来给设计好的来指定Bitmap定义密度并且inScaled属性来指定Bitmap是否缩放来匹配当前设备屏幕密度。

如果你设置inScaled为false,然后关闭系统将会在draw时期自动缩放的应用于Bitmap的预先缩放功能。

使用自动缩放代替预先缩放会占用更多CPU但是会占用更少内存。

图5展示的是当加载low(120)密度、medium(160)密度和high(240)密度在一个高密度屏幕上预先缩放和自动缩放机制的结果。只有细微的不同因为所有的Bitmap都是针对当前屏幕缩放的,尽管如此缩放的Bitmap外观还是会因为draw时是预先所昂还是自动缩放有细微的不同。


注意:在安卓3.0或者更高,由于图像框架的改进,预先缩放和自动缩放感觉不出来了。

将dp单位转化为px单位

在一些例子中,你需要用dp表示尺寸然后将他们转为像素。想想一个程序在用户的手指在屏幕上滑动或者快速滑动超过16像素就会被记录下来。在一个基线屏幕上,用户必须移动160pixels/160dpi等于一英寸(或者2.5mm)的十分之一才能被记录。在一个高密度(240dpi)设备上,用户必须移动16pixels/240dpi,等于五分之一英寸(或者1.7mm)。距离非常短程序看上去对于用户来说是非常灵敏的。

为了解决这个问题,手势在代码中必须用dp表示然后转化为实际的像素。例如:

// The gesture threshold expressed in dp,手势用dp表示
private staticfinalfloatGESTURE_THRESHOLD_DP=16.0f;

// Get the screen'sdensity scale,获取屏幕密度缩放
final float scale=getResources().getDisplayMetrics().density;
// Convert the dps topixels, based on density scale,基于密度缩放将dp转为px
mGestureThreshold = (int)(GESTURE_THRESHOLD_DP* scale+0.5f);

// UsemGestureThreshold as a distance in pixels...使用mGestureThreshold以px为单位

DisplayMetrics.density属性指定你必须使用的将dp单位转为px的缩放因子,根据当前密度。在一个medium屏幕上DisplayMetrics.density等于1.0;在high-density屏幕上等于1.5;在extra-high-density上等于2.0;在low-density屏幕上等于等于0.75。这个图是这个因子你应该乘以dp单位根据当前屏幕得到实际的像素。(然后在图的周围增加0.5来接近整数,当转化成一个整数。)更多信息,参考DisplayMetrics类。

不管怎样,不要给这个事件定义任意的门槛而是应该使用预先缩放对于ViewConfiguration可用的配置值。

使用预先缩放配置值

你可以使用ViewConfiguration类来获取普通的距离,速度以及安卓系统使用的时间。例如,框架使用的作为滚动基线的以像素为单位的距离可以通过getScaledTouchSlop()获得。

privatestaticfinalint GESTURE_THRESHOLD_DP=ViewConfiguration.get(myContext).getScaledTouchSlop();

ViewConfiguration里的以getScaled为前缀的方法保证会返回一个以像素为单位的值将会在屏幕上很好的展现不管当前屏幕的密度。

如何在多个屏幕测试你的程序

发布你的程序之前,你应该在它所支持的所有屏幕尺寸和密度上进行测试。安卓sdk包含的模拟器你可以使用,模拟器可以复制常见的屏幕尺寸和密度配置你的应用想运行的。你可以修改复制了任意指定屏幕特征的模拟器默认的尺寸,密度,分辨率。使用模拟器和附加的定制的配置允许你测试任何可能的屏幕配置,所以你不需要买各种屏幕的设备来测试你的应用支持的屏幕。

设置一个环境来测试你的应用的屏幕支持,你应该穿件一系列的AVDs(安卓虚拟设备),使用模拟器皮肤和屏幕配置模拟你的程序想支持的屏幕尺寸和密度。这样做,你可以使用AVD管理器创建AVDs并且将他们运行在一个图像界面。

运行安卓SDK管理器,执行SDK Manager.exe从你的安卓SDK目录(仅限Windows)或者从<sdk>/tools/目录执行安卓(所有平台)。图6展示的是选择了AVD的AVD管理器,用来测试各种屏幕配置。


表3展示了在安卓SDK可用的各种模拟皮肤,你可以用来模拟最常用的屏幕配置。

更多信息关于创建和使用AVDs来测试你的程序,参看Managing AVDs with AVD Manager.

表3在安卓SDK中各种可用的屏幕配置(加粗显示的)和其他典型的分辨率

Low density (120), ldpi

Medium density (160), mdpi

High density (240), hdpi

Extra-high-density (320), xhdpi

Smallscreen

QVGA (240x320)

480x640

Normalscreen

WQVGA400 (240x400) 
WQVGA432 (240x432)

HVGA (320x480)

WVGA800 (480x800) 
WVGA854 (480x854)
 
600x1024

640x960

Largescreen

WVGA800** (480x800) 
WVGA854** (480x854)

WVGA800* (480x800) 
WVGA854* (480x854)
 
600x1024

Extra-Largescreen

1024x600

WXGA (1280x800)
1024x768
1280x768

1536x1152
1920x1152 
1920x1200

2048x1536
2560x1536 
2560x1600

*为了模拟这个配置,指定一个160的自定义密度当使用WVGA800 or WVGA854创建一个AVD时

**为了模拟这个配置,指定一个120的自定义密度当使用WVGA800 or WVGA854创建一个AVD时

这个皮肤在安卓3.0可用

看任何给定屏幕配置的活动设备的相对数值,参看Screen Sizes and Densities

我们常常建议在一个设置成近似实际设备的物理尺寸的模拟器测试你的程序。这将比较各种尺寸和屏幕密度变得很容易。这样做你需要知道你的电脑显示器的用dpi表示大致密度(例如,30寸戴尔监视器是96dpi)。当你从AVD管理器运行AVD,在运行选项里你可以给模拟器指定屏幕尺寸和显示器dpi,如图7


如果你想在一个现有的屏幕没有的密度或者分辨率上测试程序,你可以创建一个AVD使用分辨率和密度。当从AVD管理器创建AVD时,指定分辨率来代替选择已有的分辨率。

如果你运行AVD在命令行模式,你可以用-scale参数指定模拟器缩放。例如:

emulator-avd<avd_name>-scale96dpi

改善模拟器的尺寸,你可以用-scale加上0.1到3的参数来表示缩放的比率。

更多关于通过命令行创建AVD的信息,参看Managing AVDs from the Command Line.

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值