原文:http://developer.android.com/intl/zh-cn/guide/practices/screens_support.html
翻译还比较粗糙,有一些地方难免不太通顺,而且文档难免繁琐和复杂,如果想看精简一点的移步:http://blog.csdn.net/program_thinker/article/details/41806135
Android运行在各种不同屏幕尺寸和密度的设备上,对于应用程序,Android系统提供了一个一致的跨设备的开发环境并且为适应不同屏幕处理绝大多数的事情。同时,为了应对更多特殊的屏幕,系统提供了各种API来优化你的应用程序界面。
虽然系统做了很多的扩展和调整,使你的应用程序能够在不同的屏幕上工作,但是你也应该做出努力,以优化在不同的屏幕大小和密度设备上的应用程序的表现。在此过程中,你最大程度的为所有设备增强用户体验,让用户体验到你的程序是为他们设备而作,而不仅仅是拉伸以适应设备屏幕。
按照文档中描述的行为,你可以使用一个apk文件创建提供支持所有屏幕配置并且显示正常的应用程序。
注意:本文档中信息假定你的应用程序为Android1.6(API 4)以及更高的版本,如果你的应用程序支持Android1.5或者更低,请写阅读Android1.5的策略。
此外,要注意Android3.2引入了新的API,让你能够为支持不同屏幕尺寸更精确控制使用的布局资源来构建你的应用程序。这些新功能是特别重要的,如果你正在开发对于平板电脑的应用程序,请参阅有关声明的平板布局Android3.2部分。
屏幕支持的概述
本节提供了Android多屏幕支持的概述,包括:API介绍,屏幕配置,总结系统使用的术语和概念,以及屏幕底层的概述
术语与概念
实际的物理尺寸,测量屏幕的对角线。
为简单起见, Android中的所有实际的屏幕尺寸分为四个广义大小:小,正常,大,和超大。
屏幕的物理区域内的像素的数量:通常被称为dpi(每英寸点数) 。例如,在给定的物理区域内一个“低”密度屏幕比 “正常”或“高”密度屏幕具有较少的像素。为简单起见, Android中的所有实际的屏幕密度分为六个广义密度:低,中,高,超高,超超高,超超超高。
从用户的角度看到的屏幕方向。一般为横向或纵向,即屏幕的宽高比。注意,不仅要关注不同的设备在缺省情况下的屏幕方向。同一设备当用户旋转时,应用程序的屏幕方向也需要关注。
分辨率
在屏幕上的物理像素的总数。当为多个屏幕添加了支持,应用程序不直接与分辨率相关:应用程序应只能与屏幕大小和密度有关,和指定的广义的大小和密度基有关。
密度无关像素(DP)
虚拟像素单元。在定义UI布局的时候,你应当使用与密度无关的方式来表示布局尺寸或者位置
密度无关的像素相当于在一个160dpi屏幕上的一个物理像素。这是一个假定在“中等”密度屏幕的基线密度。在运行时候,系统透明的处理任何缩放的DP单位,根据需要转化成屏幕的实际密度。dp的转化屏幕实际像素比较简单:px = dp * (dpi / 160)。例如,一个240dpi的屏幕上,1dp等于1.5的物理像素。定义你的应用程序UI的时候,你应该总是使用dp单位,以确保在不同密度的屏幕UI的正确显示
屏幕支持的范围
为了简化您设计针对多个屏幕的用户界面的方法,Android把实际的屏幕尺寸和密度分成如下范围:
mdpi (中) 〜 160dpi
hdpi(高) 〜 240dpi
xhdpi (超高) 〜 320dpi
xxhdpi (超超高) 〜 480dpi
xxxhdpi (超特超高) 〜 640dpi
- 超大屏幕是至少960dp X 720dp
- 大屏幕至少640dp X 480dp
- 正常屏幕至少470dp X 320dp
- 小屏幕至少426dp X 320dp
你不需要对屏幕尺寸和密度的各种组合提供备选的资源。系统提供了强大的兼容功能,可以处理你的应用程序在大多数设备屏幕上工作,前提是你使用能够调整的技术(如最佳实践说明,下同)实现您的UI。
注意:定义一个设备的屏幕尺寸和密度的特性是彼此独立的。例如,一个WVGA高密度屏幕被认为是一个正常大小的屏幕,因为它的物理尺寸和T-Mobile G1大致相同( Android的第一台设备和基准屏幕) 。另一方面,一个WVGA中密度屏幕被认为是一个大尺寸屏幕。虽然它提供了相同的分辨率(像素数相同) ,所述的WVGA中密度屏幕具有较低的屏幕密度,这意味着每个像素在物理上是较大的,因此,整个屏幕比基线(正常大小)的屏幕大。
屏幕密度独立
当你的应用实现了“密度独立”时,从用户的角度看,在不同密度屏幕显示的用户界面元素都保持了对应的物理尺寸(译者注:就是用户看起来不同屏幕体验都一样,这话说成这样真是绕)
维持密度独立性是很重要的,因为如果没有它,一个用户界面元素(如按钮)显示在低密度屏幕上比显示在高密度屏幕上在物理上更大。这样的密度有关大小的变化可能会导致你的应用程序的布局和可用性问题。图2和3表明应用程序提供或者不提供密度独立显示的差异。
图2:密度不独立的应用程序,对不同密度屏幕的显示效果
图3:密度独立的应用程序,对不同密度屏幕的显示效果
Android系统可以帮助您的应用程序实现密度独立两种方式:
- 系统为适合当前屏幕密度伸缩dp单位
- 系统根据当前屏幕密度扩展资源到合适的大小,如果需要的话
从Android 3.2 ( API等级13 )起,上述尺寸组已过时,应改用sw <n > dp配置限定符来定义你的布局资源所需的最小可用宽度。例如,如果你的平板电脑的布局至少需要600dp屏幕宽度,你应该把它放在文件夹layout-sw600dp /下 。在有关平板布局的声明在Android 3.2节进一步讨论。
- <resources_name>是标准的资源名称(例如drawable或者layout)。
- <qualifier>是表1的结构限定符。指定这些资源将被哪种屏幕配置使用(比如hdpi和xlarge)。
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/my_icon.png // bitmap for medium-density res/drawable-hdpi/my_icon.png // bitmap for high-density res/drawable-xhdpi/my_icon.png // bitmap for extra-high-density res/drawable-xxhdpi/my_icon.png // bitmap for extra-extra-high-density请注意,当Android系统选择将哪些资源在运行时使用时,它使用一定的逻辑来决定“最佳匹配”的资源。也就是说,你的限定符可以不必在所有情况下都匹配当前的屏幕配置。具体地,如果基于当前尺寸没有资源限定符很好的匹配的时候,系统会选择使用比当前屏幕小的资源(例如,如果必要的话,一个大尺寸屏幕会使用普通大小的屏幕资源) 。然而,如果唯一可用的资源比当前的大,如果没有其他的资源相匹配的设备配置,系统将不会使用它们(例如,如果所有的资源布局都标记XLARGE限定符,但设备是一个正常大小的屏幕),应用程序会崩溃。有关系统如何选择资源的更多信息,请阅读安卓如何查找最佳匹配资源(http://developer.android.com/guide/topics/resources/providing-resources.html#BestMatch)。
以下各节分别概述了你可能想使用的大小和密度限定符创建备选布局和绘图资源。
- 当在小屏幕上进行测试时,你可能会发现,你的布局并不完全适合在该屏幕上。例如,一排按钮未必适合在一个小屏幕设备上的宽度内。在这种情况下,你应该为小屏幕的替代布局调整按钮的大小或位置。
- 当在一个特大屏幕上进行测试时,你可能会意识到你的布局不能有效地利用大屏幕,并且界面元素明显拉长以填补它。在这种情况下,你应该有针对性地重新设计一个超大屏幕的替代布局。虽然你的应用程序在不使用大屏幕替代布局的时候也应该正常工作,但在用户看来,你的应用程序看起来好像是为他们的设备专门设计是非常重要的。如果UI明显拉长,用户的应用体验更可能是不满意的。
- 并且,与纵向测试相比,横向的时候,你可能会注意到,放置在纵向屏幕底部的UI元素应该放置在横向屏幕的右侧
- 适合在小屏幕上(这样用户可以实际使用应用程序)
- 对于更大的屏幕优化,充分利用额外的屏幕空间的优势
- 优化横向和纵向两个方向
- 36x36 (0.75x) for low-density
- 48x48 (1.0x baseline) for medium-density
- 72x72 (1.5x) for high-density
- 96x96 (2.0x) for extra-high-density
- 180x180 (3.0x) for extra-extra-high-density
- 192x192 (4.0x) for extra-extra-extra-high-density (launcher icon only; see note above)
- 320dp: 一款典型的手机屏幕 (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
- 480dp: 一般的平板 (480x800 mdpi).
- 600dp: 7” 平板 (600x1024 mdpi).
- 720dp: 10” 平板 (720x1280 mdpi, 800x1280 mdpi, etc).
res/layout/main_activity.xml # 对手机 res/layout-sw600dp/main_activity.xml # 对平板在这种情况下,对于使用平板布局所需的最小宽度必须是600dp。
res/layout/main_activity.xml # For handsets (smaller than 600dp available 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)注意,以上两套资源示例使用的都是“最小宽度”限定符, sw <N >dp ,其中规定了两个方向的最小屏幕,无论设备当前处在什么方位。因此,使用sw<N >dp是忽略屏幕的方向指定整体屏幕尺寸可供布局的简单方法。
- 在XML布局文件中指导尺寸时,使用wrap_content,fill_parent或者dp单位
- 不要在你的应用程序代码中使用硬编码的像素值
- 不要使用AbsoluteLayout(不建议使用)
- 提供备用的位图来绘制不同屏幕密度的图像
以下为更详细的说明
例如,对于一个layout_width=“100dp”的图,在中密度屏幕上占据100像素宽度而在高密度屏幕上扩展到150个像素,以使图在屏幕上占据大致相同的物理空间
同样的,你应该使用sp来定义文字的大小,这个sp比例因子依赖于用户设定,系统将扩展它为dp大小。
2、不要在你的应用程序代码中使用硬编码的像素值
出于性能的考虑,并为了保持代码简单,Android系统使用像素值作为表达维度或者坐标的标准单位。这意味着,一个视图的尺寸在代码中始终是用像素表示的,但这是根据当前屏幕的像素密度。例如,如果myView.getWidth()返回是10,那么认为是在当前屏幕上的10个像素,如果在具有较高密度屏幕的设备上,这个返回值可能是15。如果你应用程序代码使用像素值来处理没有缩放适配当前屏幕的位图,那么你可能需要在代码中缩放位图资源的像素值来适配当前屏幕。
3、不要使用AbsoluteLayout
不像其他的窗口布局小部件,AbsoluteLayout强制使用固定的位置来布置其子视图,这很容易导致用户界面在不同的屏幕上无法很好工作,因此AbsoluteLayout在Android1.5(API 3)已经过时。
你应该使用RelativeLayout,它对子视图使用相对的位置,例如你可以指定一个按钮控件出现在一个文本小部件的右边(“to the right of”)
4、使用大小和密度特定的资源
虽然系统可以根据当前屏幕配置的绘制资源扩展你的布局。但你仍然要为不同的屏幕尺寸的用户界面,提供不同密度优化的位图资源。这基本上是重申了本文档早期的信息
如果你需要精确的控制你的应用程序在不同屏幕配置的布局,调整特定资源目录中的布局和位图,例如,假设你要显示中,高密度的屏幕图标,简单的创建两个不同大小的图标(例如100x100中密度和150x150高密度),并放在适当的目录中,使用适当的限定符:
res/drawable-mdpi/icon.png //for medium-density screens res/drawable-hdpi/icon.png //for high-density screens注意:如果在目录名中没有定义密度限定符,那么系统将假定该目录中的资源是为中密度基线所准备的并会将其扩展以适应其他的密度
附加的密度注意事项
本节将介绍更多关于Android系统如何在不同屏幕上扩展位图资源和你如何在不同的像素密度上更进一步的控制位图的绘制。本节的信息,对于大多数应用程序不是非常重要,除非你在不同屏幕密度下运行或者你的应用程序在操作图形的时候遇到问题。
为了更好的理解怎么能够在运行操作图形时支持多种密度,你应该明白系统如何通过以下方式确保位图适当的伸缩
1、预缩放资源(比如位图资源)
基于当前的屏幕密度,系统使用你应用程序的任何大小或者特定密度的资源不进行缩放的显示它们。如果资源在当前密度不可用时,系统会加载默认资源并且根据匹配当前密度的需求适当缩放它们。系统假设默认资源(没有配置限定符文件夹下的)是专为基准屏幕像素密度而准备,除非他们从有特定密度相关的资源目录下加载。预缩放就是系统重新调整位图的大小从而适应当前的屏幕。
如果你请求预缩放资源的尺寸,系统会返回缩放后的尺寸值。例如,在mdpi上设计的一个50x50do的位图在hdpi的屏幕上会被缩放到75x75dp(如果没有应用与hdpi的备选资源)
有些情况下,你可能不希望Android预缩放资源。避免预缩放资源的方法很简单,就是创建使用nodpi为限定符的资源目录,如下所示
res/drawable-nodpi/icon.png当系统使用该目录下的位图时,系统不会基于当前屏幕像素密度缩放它。
2、自动缩放尺寸和坐标
应用可以在manifest文件中设置android:anyDensity="false"来禁止使用预缩放,或者编码设置位图资源的属性“isScaled”禁用预缩放。在这种情况下,系统在绘图时会自动缩放任意绝对像素坐标和像素尺寸值。这样做是为了确保像素定义的屏幕元素显示合适的物理尺寸。系统为应用程序透明的处理这个缩放并且报告缩放的像素尺寸给应用程序,而不是物理像素尺寸。
例如,假如一台设备具有一个480x480dp的WVGA高密度屏幕同时尺寸和传统的HVGA屏幕相同。运行的应用程序禁止了预缩放功能,在这种情况下,当查询屏幕尺寸的时候系统会依据应用,并报告320x533(近似mdpi的屏幕密度),当应用程序进行绘制操作的时候,比如画一个从(10,10)到(100,100)的长方形时,系统会根据合适的量缩放坐标,可能实际画的区域是从(15,15)到(150,150)。如果你的应用程序直接操作缩放位图,这种差异可能导致意外的行为。但是为了保持应用程序更好的表现,这被认为是一个合理的权衡。
通常情况下,你不应该禁用预缩放。支持多屏的最好方法是遵循上诉的基本技术。
如果你的应用程序操作位图或者以其他的方式与屏幕上的像素直接进行交互,你可能需要采取更多的措施来支持不同屏幕密度。例如,如果你通过手势计算手指穿过的像素数量,你需要使用密度独立的虚拟像素而不是实际像素值。
运行时缩放位图对象
如果你的应用程序创建了一个内存中的位图(一个bitmap对象)时,系统假设这个位图是为中密度的屏幕设计的。默认情况下,绘制的时候自动缩放这个位图。当位图没有特殊的密度特性时,系统对位图提供自动缩放。当你没有正确考虑设备的屏幕密度和指定位图的密度特性,自动缩放可能导致不好的效果当你不提供可替代的资源。
要控制运行时创建的位图是否缩放, 你可以使用setDensity()函数指定位图的密度,从DisplayMetrics传递一个密度,比如DENSITY_HIGH或DENSITY_LOW
如果你使用BitmapFactory(比如文件或者流)来创建位图,你可以使用BitmapFactory.Options来定义位图的属性,这可以确定是否和如何让系统缩放它。例如,你可以使用inDensity字段来位图的密度是否被设计和inScaled字段来指定位图是否应该缩放以匹配当前设备的屏幕密度。
如果你设置inScaled字段是false,那么你禁用任何缩放,系统将会自动缩放,使用自动缩放比预缩放可能更耗CPU,但使用较少内存。
图5:预缩放和自动缩放的位图比较
图5表明在高密度屏幕上加载低(120dp),中(160dp),高(240dp)密度的位图时预缩放和自动缩放的结果,差异是微小的,因为所有的位图都被缩放以匹配的当前的屏幕密度,但是略有不同的外观,这取决于是否是预缩放或者自动缩放的。
注意: 在Android3.0及以上,由于图形框架的改善,预缩放和自动缩放位图之间没有明显差异。
转化dp单位到px单位
在某些情况下,你将需要的dp尺寸转化为像素尺寸。想象一个滚动或者手势滑动应用,用户手指必须移动至少16个像素才能被识别,在基准屏幕上,一个用户必须移动16px/160dpi,等于1/10英寸(2.5毫米)才会被识别。而在一个高密度设备上(240dpi),用户只需要移动16px/240dpi,相当于1/15英寸(1.7毫米)就可以被识别,移动距离更短,应用程序应该对用户手势表现的更敏感。
要解决这个问题,手势识别必须使用dp单位,然后再转化为实际的像素,例如:
// The gesture threshold expressed in dp
private static final float GESTURE_THRESHOLD_DP = 16.0f;
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);
// Use mGestureThreshold as a distance in pixels...
根据当前屏幕密度,你必须指定DisplayMetrics.density字段作为dp单位转化为px单位的比例因子。在中等密度的屏幕,DisplayMetrics.density等于1.0;高密度等于1.5;超高密度的比例因子为2.0;在低密度时,它等于0.75.你的当前dp值必须成语这个数字才能得到当前屏幕的实际像素值(添加0.5f然后将其转换为最接近的整数)。有关的详细信息,请参阅DisplayMetrics这个类。
使用预缩放的配置值
你可以使用ViewConfiguration这个类去访问通常的距离,速度和Android系统的时间。例如,框架所使用的滚动阈值的像素距离可以用getScaledTouchSlop()函数获得:
private static final int GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).getScaledTouchSlop();
如何测试你的应用在多个屏幕上的表现
在发布你的应用程序之前,你应该彻底在它所有支持的屏幕密度和尺寸的设备上测试。Android SDK中包含了你可以使用的模拟器,它是复制了常见的密度和尺寸大小的仿真样式机,你也可以调整模拟器的尺寸和密度。所以你可以通过使用模拟器而不必为了你的应用程序屏幕支持而购买各种设备。
图6:一套为测试屏幕支持的模拟机
要创建测试你的应用程序的屏幕支持的环境,你必须创建一系列模拟机(Android虚拟设备)。模仿出你喜欢你的应用程序支持的屏幕大小和密度。要做到这点,你可以使用AVD管理器创建他们。
为运行Android SDK管理器,打开你Android SDK目录下的执行文件manage.exe(仅在Windows上),或者从<sdk>/tools/directory(所有平台)执行android。图6显示了AVD管理一系列的AVDs
表3显示了Android SDK显示的各种仿真机型,你可以用它来模拟一些常见的屏幕配置。
有关创建和使用AVD来测试您的应用程序,更多信息请看http://developer.android.com/tools/devices/managing-avds.html
表3:Android SDK中各种屏幕配置模拟器
我们还建议你设置紧密匹配你实际设备物理尺寸的模拟器来运行你的程序,这让它的测试结果更加可靠。为了做到这点,你必须知道你的电脑显示器的大致的密度(dpi),比如,一个30“戴尔显示器拥有96dpi的密度。当你从AVD管理器启动一个AVD,你可以指定模拟机的屏幕,并启动显示器DPI选项,如图7
图7:启动AVD时设置大小和密度
当你的想测试的屏幕尺寸或者密度内置的机型不支持,你可以创建一个自定义分辨率或者密度的AVD,当你从AVD管理器中创建AVD时候,指定而不是选择一个分辨率(或者密度)。
如果你用命令行启动AVD,你可以使用-scale选项来指定模拟器的scale。例如:
emulator -avd <avd_name> -scale 96dpi
有关通过命令行创建AVD的更多信息,请参阅http://developer.android.com/tools/devices/managing-avds-cmdline.html
OVER
啃下来真是累。。。废话太多准备总结一下出点干货
还有英文有限,翻译的不好的地方请大家指正