[This post is by Dianne Hackborn and a supporting cast of thousands; Dianne’s fingerprints can be found all over the Android Application Framework — Tim Bray]
Android 3.2 includes new tools for supporting devices with a wide range of screen sizes. One important result is better support for a new size of screen; what is typically called a “7-inch” tablet. This release also offers several new APIs to simplify developers’ work in adjusting to different screen sizes.
This a long post. We start by discussing the why and how of Android “dp” arithmetic, and the finer points of the screen-size buckets. If you know all that stuff, you can skip down to “Introducing Numeric Selectors” to read about what’s new. We also provide our recommendations for how you can do layout selection in apps targeted at Android 3.2 and higher in a way that should allow you to support the maximum number of device geometries with the minimum amount of effort.
Of course, the official write-up on Supporting Multiple Screens is also required reading for people working in this space.
Understanding Screen Densities and the “dp”
Resolution is the actual number of pixels available in the display, density is how many pixels appear within a constant area of the display, and size is the amount of physical space available for displaying your interface. These are interrelated: increase the resolution and density together, and size stays about the same. This is why the 320x480 screen on a G1 and 480x800 screen on a Droid are both the same screen size: the 480x800 screen has more pixels, but it is also higher density.
To remove the size/density calculations from the picture, the Android framework works wherever possible in terms of "dp" units, which are corrected for density. In medium-density ("mdpi") screens, which correspond to the original Android phones, physical pixels are identical to dp's; the devices’ dimensions are 320x480 in either scale. A more recent phone might have physical-pixel dimensions of 480x800 but be a high-density device. The conversion factor from hdpi to mdpi in this case is 1.5, so for a developer's purposes, the device is 320x533 in dp's.
Screen-size Buckets
Android has included support for three screen-size “buckets” since 1.6, based on these “dp” units: “normal” is currently the most popular device format (originally 320x480, more recently higher-density 480x800); “small” is for smaller screens, and “large” is for “substantially larger” screens. Devices that fall in the “large” bucket include the Dell Streak and original 7” Samsung Galaxy Tab. Android 2.3 introduced a new bucket size “xlarge”, in preparation for the approximately-10” tablets (such as the Motorola Xoom) that Android 3.0 was designed to support.
The definitions are:
-
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. (Android does not currently support screens smaller than this.)
Here are some more examples of how this works with real screens:
-
A QVGA screen is 320x240 ldpi. Converting to mdpi (a 4/3 scaling factor) gives us 426dp x 320dp; this matches the minimum size above for the small screen bucket.
-
The Xoom is a typical 10” tablet with a 1280x800 mdpi screen. This places it into the xlarge screen bucket.
-
The Dell Streak is a 800x480 mdpi screen. This places it into the bottom of the large size bucket.
-
A typical 7” tablet has a 1024x600 mdpi screen. This also counts as a large screen.
-
The original Samsung Galaxy Tab is an interesting case. Physically it is a 1024x600 7” screen and thus classified as “large”. However the device configures its screen as hdpi, which means after applying the appropriate ⅔ scaling factor the actual space on the screen is 682dp x 400dp. This actually moves it out of the “large” bucket and into a “normal” screen size. The Tab actually reports that it is “large”; this was a mistake in the framework’s computation of the size for that device that we made. Today no devices should ship like this.
Issues With Buckets
Based on developers’ experience so far, we’re not convinced that this limited set of screen-size buckets gives developers everything they need in adapting to the increasing variety of Android-device shapes and sizes. The primary problem is that the borders between the buckets may not always correspond to either devices available to consumers or to the particular needs of apps.
The “normal” and “xlarge” screen sizes should be fairly straightforward as a target: “normal” screens generally require single panes of information that the user moves between, while “xlarge” screens can comfortably hold multi-pane UIs (even in portrait orientation, with some tightening of the space).
The “small” screen size is really an artifact of the original Android devices having 320x480 screens. 240x320 screens have a shorter aspect ratio, and applications that don’t take this into account can break on them. These days it is good practice to test user interfaces on a small screen to ensure there are no serious problems.
The “large” screen size has been challenging for developers — you will notice that it encompases everything from the Dell Streak to the original Galaxy Tab to 7" tablets in general. Different applications may also reasonably want to take different approaches to these two devices; it is also quite reasonable to want to have different behavior for landscape vs. portrait large devices because landscape has plenty of space for a multi-pane UI, while portrait may not.
Introducing Numeric Selectors
Android 3.2 introduces a new approach to screen sizes, with the goal of making developers' lives easier. We have defined a set of numbers describing device screen sizes, which you can use to select resources or otherwise adjust your UI. We believe that using these will not only reduce developers’ workloads, but future-proof their apps significantly.
The numbers describing the screen size are all in “dp” units (remember that your layout dimensions should also be in dp units so that the system can adjust for screen density). They are:
-
width dp: the current width available for application layout in “dp” units; changes when the screen switches orientation between landscape and portrait.
-
height dp: the current height available for application layout in “dp” units; also changes when the screen switches orientation.
-
smallest width dp: the smallest width available for application layout in “dp” units; this is the smallest width dp that you will ever encounter in any rotation of the display.
Of these, smallest width dp is the most important. It replaces the old screen-size buckets with a continuous range of numbers giving the effective size. This number is based on width because that is fairly universally the driving factor in designing a layout. A UI will often scroll vertically, but have fairly hard constraints on the minimum space it needs horizontally; the available width is also the key factor in determining whether to use a phone-style one-pane layout or tablet-style multi-pane layout.
Typical numbers for screen width dp are:
-
320: a phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
-
480: a tweener tablet like the Streak (480x800 mdpi).
-
600: a 7” tablet (600x1024).
-
720: a 10” tablet (720x1280, 800x1280, etc).
Using the New Selectors
When you are designing your UI, the main thing you probably care about is where you switch between a phone-style UI and a tablet-style multi-pane UI. The exact point of this switch will depend on your particular design — maybe you need a full 720dp width for your tablet layout, maybe 600dp is enough, or 480dp, or even some other number between those. Either pick a width and design to it; or after doing your design, find the smallest width it supports.
Now you can select your layout resources for phones vs. tablets using the number you want. For example, if 600dp is the smallest width for your tablet UI, you can do this:
res/layout/main_activity.xml # For phones res/layout-sw600dp/main_activity.xml # For tablets
For the rare case where you want to further customize your UI, for example for 7” vs. 10” tablets, you can define additional smallest widths:
res/layout/main_activity.xml # For phones res/layout-sw600dp/main_activity.xml # For 7” tablets res/layout-sw720dp/main_activity.xml # For 10” tablets
Android will pick the resource that is closest to the device’s “smallest width,” without being larger; so for a hypothetical 700dp x 1200dp tablet, it would pick layout-sw600dp.
If you want to get fancier, you can make a layout that can change when the user switches orientation to the one that best fits in the current available width. This can be of particular use for 7” tablets, where a multi-pane layout is a very tight fit in portrait::
res/layout/main_activity.xml # Single-pane res/layout-w600dp/main_activity.xml # Multi-pane when enough width
Or the previous three-layout example could use this to switch to the full UI whenever there is enough width:
res/layout/main_activity.xml # For phones res/layout-sw600dp/main_activity.xml # Tablets res/layout-sw600dp-w720dp/main_activity.xml # Large width
In the setup above, we will always use the phone layout for devices whose smallest width is less than 600dp; for devices whose smallest width is at least 600dp, we will switch between the tablet and large width layouts depending on the current available width.
You can also mix in other resource qualifiers:
res/layout/main_activity.xml # For phones res/layout-sw600dp/main_activity.xml # Tablets res/layout-sw600dp-port/main_activity.xml # Tablets when portrait
Selector Precedence
While it is safest to specify multiple configurations like this to avoid potential ambiguity, you can also take advantage of some subtleties of resource matching. For example, the order that resource qualifiers must be specified in the directory name (documented in Providing Resources) is also the order of their “importance.” Earlier ones are more important than later ones. You can take advantage of this to, for example, easily have a landscape orientation specialization for your default layout:
res/layout/main_activity.xml # For phones res/layout-land/main_activity.xml # For phones when landscape res/layout-sw600dp/main_activity.xml # Tablets
In this case when running on a tablet that is using landscape orientation, the last layout will be used because the “swNNNdp” qualifier is a better match than “port”.
Combinations and Versions
One final thing we need to address is specifying layouts that work on both Android 3.2 and up as well as previous versions of the platform.
Previous versions of the platform will ignore any resources using the new resource qualifiers. This, then, is one approach that will work:
res/layout/main_activity.xml # For phones res/layout-xlarge/main_activity.xml # For pre-3.2 tablets res/layout-sw600dp/main_activity.xml # For 3.2 and up tablets
This does require, however, that you have two copies of your tablet layout. One way to avoid this is by defining the tablet layout once as a distinct resource, and then making new versions of the original layout resource that point to it. So the layout resources we would have are:
res/layout/main_activity.xml # For phones res/layout/main_activity_tablet.xml # For tablets
To have the original layout point to the tablet version, you put <item>
specifications in the appropriate values directories. That is these two files:
res/values-xlarge/layout.xml res/values-sw600dp/layout.xml
Both would contain the following XML defining the desired resource:
<?xml version="1.0" encoding="utf-8"?> <resources> <item type="layout" name="main_activty"> @layout/main_activity_tablet </item> </resources>
Of course, you can always simply select the resource to use in code. That is, define two or more resources like “layout/main_activity” and “layout/main_activity_tablet,” and select the one to use in your code based on information in the Configuration object or elsewhere. For example:
public class MyActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(); Configuration config = getResources().getConfiguration(); if (config.smallestScreenWidthDp >= 600) { setContentView(R.layout.main_activity_tablet); } else { setContentView(R.layout.main_activity); } } }
Conclusion
We strongly recommend that developers start using the new layout selectors for apps targeted at Android release 3.2 or higher, as we will be doing for Google apps. We think they will make your layout choices easier to express and manage.
Furthermore, we can see a remarkably wide variety of Android-device form factors coming down the pipe. This is a good thing, and will expand the market for your work. These new layout selectors are specifically designed to make it straightforward for you to make your apps run well in a future hardware ecosystem which is full of variety (and surprises).
新的工具来管理屏幕尺寸
本帖是戴安娜Hackborn,数千一个配角; 戴安娜的指纹遍布Android应用程序框架中找到蒂姆 - 布雷]
Android 3.2的包括用于与各种屏幕尺寸的配套装置新的工具。一个重要的结果是屏幕的新大小更好的支持; 什么通常称为“7英寸”片剂。此版本还提供了一些新的API,以简化在适应不同的屏幕尺寸开发人员的工作。
这是一个长的帖子。我们通过讨论为什么和如何的Android的“DP”算术启动,并在屏幕尺寸桶的细微之处。如果你知道所有的东西,你可以跳过了“引进数字选择器”,以了解什么是新的。我们还为你如何能做到布局中选择的方式,应该让你支持设备的几何形状的最大数目的努力的最低金额为Android 3.2及更高目标应用程序的建议。
当然,官方写了支持多种屏幕,还需要读书的人在这个领域的工作。
了解屏幕密度和“DP”
分辨率是在显示可用像素的实际数量,密度是多少像素如何出现在显示器的恒定区域内,并且尺寸是物理空间可用于显示的接口的数量。这些是相互关联的:提高分辨率和密度在一起,大小保持大约相同。这就是为什么分辨率320x480屏幕上的G1和480x800的屏幕上的一个德罗伊德都是相同的屏幕尺寸:480×800屏幕有更多的像素,但它也是更高的密度。
要删除的图片尺寸/密度计算,Android框架工作中尽可能的“DP”,这些密度修正条款。在中密度(“MDPI”)的屏幕,其相应于原始的Android手机,物理像素是相同的DP的; 该器件的尺寸在任何分辨率320x480规模。最近的一个电话可能为480x800的物理像素尺寸,但是是一个高密度的设备。从HDPI的转换系数在这种情况下,以MDPI是1.5,所以开发人员的目的,该装置是在DP的320x533。
屏幕尺寸的铲斗
Android已经包含了三屏大小的“桶”的支持,因为1.6的基础上,这些“DP”单位:“正常”是当前最流行的设备的格式(分辨率320x480原来,最近高密度的480×800); “小”是较小的屏幕,而“大”是“大得多”屏幕。那年秋天,在“大”斗设备包括戴尔Streak和原有的7“三星Galaxy Tab。Android 2.3的推出了新的桶大小“XLARGE”,准备约-10“平板电脑(如摩托罗拉Xoom)是Android 3.0的旨在支持。
的含义是:
-
XLARGE屏幕是至少960dp点¯x720dp。
-
大屏幕至少640dp点¯x480dp。
-
标准屏幕至少470dp点¯x320dp。
-
小屏幕至少426dp点¯x320dp。(Android版目前不支持比这更小的屏幕。)
下面是如何工作与真正的屏幕更多的例子:
-
一个QVGA屏幕为320x240 LDPI。转换为MDPI(4/3比例因子)为我们提供了426dp点¯x320dp; 这符合上面的小屏幕桶的最小尺寸。
-
Xoom的是一个典型的10“平板电脑与1280x800的屏幕MDPI。这会将其放入XLARGE屏幕桶。
-
在戴尔Streak是一种800X480的屏幕MDPI。此放置入大尺寸桶的底部。
-
一个典型的7“平板电脑拥有1024x600的屏幕MDPI。这也算作一个大屏幕。
-
原来的三星Galaxy Tab是一个有趣的案例。物理上它是一个1024x600的7“屏,因此归类为”大“。然而,设备配置其屏幕HDPI,施加适当⅔比例因子之后,这意味着在屏幕上的实际空间是682dp点¯x400dp。这实际上移动它了“大”斗,并成为一个“正常”的屏幕尺寸。该标签实际报告说,它是“大”; 这是在大小该设备,我们做框架的计算是错误的。今天,没有任何设备出货应该像这样。
问题水桶
根据开发商的经验,到目前为止,我们不相信这一套有限的屏幕尺寸桶给它们在适应不断增加多款Android设备的形状和大小都需要开发者的一切。的主要问题是,在水桶之间的边界可能不总是对应于提供给消费者或应用的特定需要或设备。
“正常”和“XLARGE”屏幕尺寸应作为目标相当简单:“正常”的屏幕通常需要的信息之间的用户移动,而“XLARGE”屏幕可以舒适地容纳多窗格的UI(即使纵向单窗格取向,与空间的一些紧缩)。
“小”的屏幕尺寸是真的有小320x480的屏幕原生Android设备的神器。240×320的屏幕有一个较短的长宽比,并且不考虑到这一点的应用程序可以在他们身上打破。这些天,这是很好的做法,在小屏幕上进行测试的用户界面,以确保不存在严重的问题。
在“大”屏幕尺寸已具有挑战性的开发商 - 你会发现,它encompases一切从戴尔Streak到原来的Galaxy Tab 7“一般平板电脑不同的应用程序也可以合理需要采取不同的方法,以这两种设备。这也是很有道理的希望有横向和纵向的大设备不同的行为,因为景观有大量的多窗格界面空间,同时肖像可能不会。
介绍数字选择器
Android 3.2的引入了一种新的方法来屏幕尺寸,制作与开发者的生活更轻松的目标。我们已经定义了一套描述设备的屏幕尺寸,你可以用它来选择资源或以其他方式调整UI数字。我们相信,使用这些不但可以减少开发的工作量,而且满足未来的应用显著。
描述屏幕大小的数字都在“DP”单位(记住,你的布局方面也应该在dp为单位,以使系统可以调整屏幕密度)。他们是:
-
宽度DP:可用于“DP”单位应用程序布局当前的宽度; 当屏幕横向和纵向之间切换的方向变化。
-
高度DP:可用于“DP”单位应用程序布局当前高度; 当屏幕切换方向也会改变。
-
最小宽度DP:可用于“DP”单位应用程序布局的最小宽度; 这是你将永远在屏幕的任何旋转遇到的最小宽度DP。
这些中,最小宽度Dp是最重要的。它取代了旧屏幕尺寸的桶用连续数字范围给予有效尺寸。这个数字是根据宽度,因为这是相当普遍,在设计布局中的驱动因素。一个UI往往会垂直滚动,但它需要横向的最小空间相当硬约束; 可用宽度也是决定是否使用手机式单面板布局或平板电脑式的多面板布局的关键因素。
对于屏幕宽度DP典型值是:
-
320:手机屏幕(240×320 LDPI,MDPI分辨率320x480,480x800的华电国际等)。
-
480:一个中间人的平板电脑,如条纹(480x800的MDPI)。
-
600:7“平板电脑(600x1024)。
-
720:10“平板电脑(720x1280,800x1280等)。
使用新的选择器
当你设计你的UI,你可能关心的主要事情是你一个手机式UI和平板电脑式的多窗格界面之间切换。该开关的确切地点将取决于特定的设计 - 也许你需要一个完整的720dp宽度平板电脑的布局,也许600dp就足够了,或者480dp,还是那些之间甚至一些其他的数字。无论是选择一个宽度和设计它; 或做你的设计之后,发现它支持的最小宽度。
现在你可以使用你想要的数字手机与平板电脑选择的布局资源。例如,如果600dp就为您的平板电脑界面的最小宽度,你可以这样做:
RES / 布局/ main_activity 。XML #对于手机 RES / 布局- sw600dp / main_activity 。XML #对于平板电脑
对于您想进一步自定义您的用户界面,例如,对于7“与10”平板电脑的极少数情况下,您可以定义附加最小宽度:
RES / 布局/ main_activity 。XML #对于手机 RES / 布局- sw600dp / main_activity 。XML #对于7“平板电脑 RES / 布局- sw720dp / main_activity 。XML #对于10”片
Android将挑选最接近设备的资源“最小宽度”,而不需要更大; 这样一个假设700dp点¯x1200dp平板电脑,它会选择布局sw600dp。
如果你想更大胆的尝试,你可以做一个布局,当用户切换方向到当前可用宽度最适合的一个可以改变的。这可以是特定用途的为7“的片剂,其中,多窗格布局是一个非常紧配合在纵向::
RES / 布局/ main_activity 。XML #单窗格 RES / 布局- w600dp / main_activity 。XML #多面板当足够宽度
或者前三个布局例如可以使用它来切换到完整的UI,只要有足够的宽度:
RES / 布局/ main_activity 。XML #对于手机 RES / 布局- sw600dp / main_activity 。XML #片 RES / 布局- sw600dp - w720dp / main_activity 。XML #大宽度
在上面的设置中,我们将始终使用的设备,其最小宽度小于600dp的手机布局; 对于设备的最小宽度至少为600dp,我们将片剂和根据当前的可用宽度大的宽度的布局之间进行切换。
你也可以混合在其他资源预选赛:
RES / 布局/ main_activity 。XML #对于手机 RES / 布局- sw600dp / main_activity 。XML #片 RES / 布局- sw600dp - 端口/ main_activity 。XML #片肖像时
优先选择
虽然这是最安全的方式指定多个配置,这样避免潜在的不确定性,还可以采取资源匹配的一些细微之处的优势。例如,资源预选赛必须在目录名中指定的顺序(文档中提供了参考资料)也是他们的秩序“的重要性。”此前那些比后来者更重要。你可以利用这一点,例如,轻松拥有一个横向专业化的默认布局:
RES / 布局/ main_activity 。XML #对于手机 RES / 布局- 土地/ main_activity 。XML #对于手机时的景观 资源/ 布局- sw600dp / main_activity 。XML #片
在正在使用横向片剂运行时这种情况下,最后的布局将被使用,因为“swNNNdp”限定符是比“端口”更匹配。
组合和版本
我们需要解决的最后一件事是指定同时在Android 3.2工作,行动,以及该平台的早期版本布局。
该平台的早期版本将使用新的资源预选赛忽略任何资源。那么,这是一种方法,将工作:
RES / 布局/ main_activity 。XML #对于手机 RES / 布局- XLARGE / main_activity 。XML #对于预3.2片 RES / 布局- sw600dp / main_activity 。XML #3.2及以上平板电脑
然而,这确实需要,你有你的平板电脑布局的两个副本。避免这种情况的一种方法是,一旦定义了平板电脑的布局作为一个独特的资源,然后使指向它原来的布局资源的新版本。因此,我们将有布局资源有:
RES / 布局/ main_activity 。XML #对于手机 RES / 布局/ main_activity_tablet 。XML #对于平板电脑
有原来 的布局点到平板电脑的版本,你放的<item>
在适当的值目录的规范。即这两个文件:
RES / 值- XLARGE / 布局。XML RES / 值- sw600dp / 布局。XML
双方将包含以下XML定义所需的资源:
<?xml的version = "1.0" encoding = "utf-8" ?> <resources> <item type = "layout" name = "main_activty" > @layout/main_activity_tablet </item> </resources>
当然,你总是可以简单地选择在代码中使用资源。也就是说,定义了两个或更多的资源,如“布局/ main_activity”和“布局/ main_activity_tablet”,然后选择一个基于配置对象或其他信息在你的代码中使用。例如:
public class MyActivity extends Activity { @Override protected void onCreate ( Bundle savedInstanceState ) { super . onCreate (); Configuration config = getResources (). getConfiguration (); if ( config . smallestScreenWidthDp >= 600 ) { setContentView ( R . layout . main_activity_tablet ); } else { setContentView ( R . layout . main_activity ); } } }
结论
我们强烈建议使用开发新的布局选择器针对Android应用发布3.2或更高版本,因为我们会做的谷歌应用程序启动。我们认为,它们会使你的布局选择,更容易表达和管理。
此外,我们可以看到一个显着各种各样的灌进管道的Android设备的外形。这是一件好事,并且将扩大市场对你的工作。这些新的布局选择器是专门设计,使之简单为你让你的应用在未来的硬件生态系统里面充满了各种(和惊喜)的良好运行。