This lesson teaches you to
- Use "wrap_content" and "match_parent" 使用“wrap_content”和“match_parent”
- Use RelativeLayout 使用RelativeLayout
- Use Size Qualifiers 使用屏幕尺寸限制
- Use the Smallest-width Qualifier 使用最小宽度限制
- Use Layout Aliases 使用布局别名
- Use Orientation Qualifiers 使用方向限制
- Use Nine-patch Bitmaps 使用点九图片
You should also read
- Supporting Multiple Screens
Try it out
NewsReader.zip
This lesson shows you how to support different screen sizes by: 这节课向你展示了如何支持不同尺寸的屏幕:
- Ensuring your layout can be adequately resized to fit the screen 确保你可以充分调整大小以适合屏幕布局
- Providing appropriate UI layout according to screen configuration 根据屏幕配置提供适当的UI布局
- Ensuring the correct layout is applied to the correct screen 确保正确的布局应用于正确的屏幕
- Providing bitmaps that scale correctly 提供正确规格的位图
Use "wrap_content" and "match_parent"
To ensure that your layout is flexible and adapts to different screen sizes, you should use "wrap_content"
and"match_parent"
for
the width and height of some view components. If you use "wrap_content"
, the width or height of the view is set to the minimum size necessary to fit
the content within that view, while "match_parent"
(also known as"fill_parent"
before
API level 8) makes the component expand to match the size of its parent view.
为了确保你的布局灵活,适应不同的屏幕尺寸,您应该使用“wrap_content”和“match_parent”定义一些视图组件的宽度和高度。如果你使用“wrap_content”设置视图的宽度或高度适合视图的内容所需的最小尺寸,而“match_parent”(也称为“fill_parent”API级别8)使组件扩大,与它的父视图的大小相匹配。
By using the "wrap_content"
and "match_parent"
size
values instead of hard-coded sizes, your views either use only the space required for that view or expand to fill the available space, respectively. For example:
通过使用“wrap_content”和“match_parent”,而不是硬编码设置大小,你的视图既可以只使用所需的空间又可以扩大填补空间。例如:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:id="@+id/linearLayout1" android:gravity="center" android:layout_height="50dp"> <ImageView android:id="@+id/imageView1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/logo" android:paddingRight="30dp" android:layout_gravity="left" android:layout_weight="0" /> <View android:layout_height="wrap_content" android:id="@+id/view1" android:layout_width="wrap_content" android:layout_weight="1" /> <Button android:id="@+id/categorybutton" android:background="@drawable/button_bg" android:layout_height="match_parent" android:layout_weight="0" android:layout_width="120dp" style="@style/CategoryButtonStyle"/> </LinearLayout> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
Notice how the sample uses "wrap_content"
and"match_parent"
for
component sizes rather than specific dimensions. This allows the layout to adapt correctly to different screen sizes and orientations.
注意,示例使用“wrap_content”和“match_parent”定义组件的大小,而不是固定的大小。这允许布局正确适应不同屏幕大小和方向.
For example, this is what this layout looks like in portrait and landscape mode. Notice that the sizes of the components adapt automatically to the width and height:
例如,这就是此布局看起来像在垂直和水平模式。注意组件的大小自动调整宽度和高度:
Figure 1. The News Reader sample app in portrait (left) and landscape (right).
Use RelativeLayout
You can construct fairly complex layouts using nested instances of LinearLayout
and combinations of"wrap_content"
and "match_parent"
sizes.
However,LinearLayout
does not allow you to precisely control the spacial relationships of child views; views in a LinearLayout
simply
line up side-by-side. If you need child views to be oriented in variations other than a straight line, a better solution is often to use a RelativeLayout
,
which allows you to specify your layout in terms of the spacial relationships between components. For instance, you can align one child view on the left side and another view on the right side of the screen.
您可以使用LinearLayout里面包含“wrap_content”和“match_parent”,构造相当复杂的布局组合。然而,LinearLayout不允许您精确控制子视图之间的关系;LinearLayout在视图中线性排列。如果你需要子视图比一条直线,在方向上有更多的变化,一个更好的解决方案通常是使用RelativeLayout,它允许您指定您的布局的组件之间的空间关系。例如,您可以使一个子视图在另一个视图的左侧,而这个视图在屏幕的右侧。
For example:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/label" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Type here:"/> <EditText android:id="@+id/entry" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/label"/> <Button android:id="@+id/ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/entry" android:layout_alignParentRight="true" android:layout_marginLeft="10dp" android:text="OK" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@id/ok" android:layout_alignTop="@id/ok" android:text="Cancel" /> </RelativeLayout>
Figure 2 shows how this layout appears on a QVGA screen.
Figure 2. Screenshot on a QVGA screen (small screen).
Figure 3 shows how it appears on a larger screen.
Figure 3. Screenshot on a WSVGA screen (large screen).
Notice that although the size of the components changed, their spatial relationships are preserved as specified by theRelativeLayout.LayoutParams
.
注意,组件大小的改变,他们的空间关系是在RelativeLayout.LayoutParams中保存。
Use Size Qualifiers
There‘s only so much mileage you can get from a flexible layout or relative layout like the one in the previous sections. While those layouts adapt to different screens by stretching the space within and around components, they may not provide the best user
experience for each screen size. Therefore, your application should not only implement flexible layouts, but should also provide several alternative layouts to target different screen configurations. You do so by using configuration
qualifiers, which allows the runtime to automatically select the appropriate resource based on the current device’s configuration (such as a different layout design for different screen sizes).
前面的部分讲了很多的例子,你可以灵活布局。而那些布局拉伸空间适应不同屏幕以及周边组件,他们可能无法提供最好的用户体验为每个屏幕大小,因此应用程序不仅要实现灵活的布局,还应该为几种不同的布局目标提供不同的屏幕配置。你这样做配置限定,它允许运行时根据当前设备的配置自动选择适当的资源(如为不同的屏幕尺寸设计不同的布局)。
For example, many applications implement the "two pane" pattern for large screens (the app might show a list of items on one pane and the content on another pane). Tablets and TVs are large enough for both panes to fit simultaneously on screen, but phone screens
have to show them separately. So, to implement these layouts, you could have the following files:
例如,许多应用程序可以对大屏幕实现“两个窗格”模式。(应用程序会在一个窗格显示项目列表和在另一个窗格显示内容)。平板电脑和电视都有足够大的窗格,可以同时适合屏幕,但手机屏幕必须分别显示。所以,要实现这些布局,你可以有以下文件:
res/layout/main.xml
, single-pane (default) layout:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
res/layout-large/main.xml
, two-pane layout:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="400dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent" /> </LinearLayout>
Notice the large
qualifier in the directory name of the second layout. This layout will be selected on devices with screens classified as large (for
example, 7" tablets and above). The other layout (without qualifiers) will be selected for smaller devices.
例如,许多应用程序可以对大屏幕实现“两个窗格”模式。(应用程序会在一个窗格显示项目列表和在另一个窗格显示内容)。平板电脑和电视都有足够大的窗格,可以同时适合屏幕,但手机屏幕必须分别显示。所以,要实现这些布局,你可以有以下文件:
Use the Smallest-width Qualifier
One of the difficulties developers had in pre-3.2 Android devices was the "large" screen size bin, which encompasses the Dell Streak, the original Galaxy Tab, and 7" tablets in general. However, many applications may want to show different layouts for different
devices in this category (such as for 5" and 7" devices), even though they are all considered to be "large" screens. That‘s why Android introduced the "Smallest-width" qualifier (amongst others) in Android 3.2.
开发Andrioid3.2之前的大屏幕设备对于开发者来说是比较困难的,这包括戴尔Streak和最初的Galaxy Tab,以及7英寸平板电脑。许多应用程序可能需要显示不同的布局在不同的设备上(如5寸和7寸设备),即使他们都认为是大屏幕,但是依然会有出现不兼容的现象。这就是为什么Android3.2推出“Smallest-width”限定符的原因。
The Smallest-width qualifier allows you to target screens that have a certain minimum width given in dp. For example, the typical 7" tablet has a minimum width of 600 dp, so if you want your UI to have two panes on those screens (but a single list on smaller
screens), you can use the same two layouts from the previous section for single and two-pane layouts, but instead of the large
size qualifier, usesw600dp
to
indicate the two-pane layout is for screens on which the smallest-width is 600 dp:
Smallest-width限定允许目标屏幕的最小宽度使用dp。例如,典型的7英寸平板电脑的最小宽度时600dp,所以如果你想让你的用户界面在屏幕上有两个窗格(但较小的屏幕是列表),您可以使用sw600dp指示屏幕显示两个窗格的布局。
res/layout/main.xml
, single-pane (default) layout:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
res/layout-sw600dp/main.xml
, two-pane layout:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="400dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent" /> </LinearLayout>
This means that devices whose smallest width is greater than or equal to 600dp will select the layout-sw600dp/main.xml
(two-pane) layout, while smaller
screens will select thelayout/main.xml
(single-pane) layout.
这意味着设备的最小宽度大于或等于600dp将选择layout-sw600dp中的布局文件。,而较小的屏幕将选择layout下的布局文件。
However, this won‘t work well on pre-3.2 devices, because they don‘t recognize sw600dp
as a size qualifier, so you still have to use the large
qualifier
as well. So, you should have a file named res/layout-large/main.xml
which is identical tores/layout-sw600dp/main.xml
.
In the next section you‘ll see a technique that allows you to avoid duplicating the layout files this way.
然而,这不会在Android3.2之前的设备上工作得很好,因为他们不认识sw600dp大小限定,所以你仍然需要使用large限定。所以,你应该有一个名为res / layout-large /文件夹。与res / layout-sw600dp /布局文件相同。在下一节中,您将看到一种技术,允许您避免重复这样的布局文件。
Use Layout Aliases
The smallest-width qualifier is available only on Android 3.2 and above. Therefore, you should also still use the abstract size bins (small, normal, large and xlarge) to be compatible with earlier versions. For example, if you want to design your UI so that
it shows a single-pane UI on phones but a multi-pane UI on 7" tablets, TVs and other large devices, you‘d have to supply these files:
smallest-width限定符只在Android3.2及以上是可用的。因此,你应该使用大小限定文件夹(小的、正常的,大的和超大)与早期版本兼容。举个例子,如果你想设计你的UI,它显示了一个电影里的手机UI和多窗格 7”平板电脑UI、电视和其它大型设备,你必须提供这些文件:
res/layout/main.xml:
single-pane layoutres/layout-large:
multi-pane layoutres/layout-sw600dp:
multi-pane layout
The last two files are identical, because one of them will be matched by Android 3.2 devices, and the other one is for the benefit of tablets and TVs with earlier versions of Android.
最后两个文件是相同的,因为其中一个将由Android 3.2设备匹配,另一个是与早期版本的Android平板电脑和电视匹配。
To avoid this duplication of the same file for tablets and TVs (and the maintenance headache resulting from it), you can use alias files. For example, you can define the following layouts:
为了避免匹配平板和电视(以及将来维护)出现这种重复相同的文件,您可以使用别名文件。例如,您可以定义以下布局:
res/layout/main.xml
, single-pane layoutres/layout/main_twopanes.xml
, two-pane layout
And add these two files:
res/values-large/layout.xml
:<resources> <item name="main" type="layout">@layout/main_twopanes</item> </resources>
res/values-sw600dp/layout.xml
:<resources> <item name="main" type="layout">@layout/main_twopanes</item> </resources>
These latter two files have identical content, but they don’t actually define the layout. They merely set up main
to be an alias to main_twopanes
.
Since these files have large
andsw600dp
selectors,
they are applied to tablets and TVs regardless of Android version (pre-3.2 tablets and TVs matchlarge
, and post-3.2 will match sw600dp
).
这两个文件有相同的内容,但他们实际上并不定义布局。他们只是设置main_twopanes别名。因为这些文件拥有large和sw600dp选择器,它们被应用到Android任何版本平板和电视上。(sw600dp将匹配Android3.2之前的版本的平板和电视机以及Anroid3.2之后的)。
Use Orientation Qualifiers 使用方向限定符
Some layouts work well in both landscape and portrait orientations, but most of them can benefit from adjustments. In the News Reader sample app, here is how the layout behaves in each screen size and orientation:
一些横向和纵向布局工作,但大多数人可以受益于调整。在新闻阅读器上示例应用程序,这是如何布局的行为在每个屏幕上的大小和方向:
- small screen, portrait: single pane, with logo
- 小屏幕,竖屏:单一窗格中,标识
- small screen, landscape: single pane, with logo
- 小屏幕、横屏 :单窗格,标志
- 7" tablet, portrait: single pane, with action bar
- 7寸平板电脑,竖屏:单面板,操作栏
- 7" tablet, landscape: dual pane, wide, with action bar
- 7寸平板电脑、横屏:双面板,宽,操作栏
- 10" tablet, portrait: dual pane, narrow, with action bar
- 10英寸的平板电脑,竖屏 :双面板,狭窄,操作栏
- 10" tablet, landscape: dual pane, wide, with action bar
- 10英寸平板电脑、横屏:双面板,宽,操作栏
- TV, landscape: dual pane, wide, with action bar
- 电视、横屏 :双面板,宽,操作栏
So each of these layouts is defined in an XML file in theres/layout/
directory. To then assign each layout to the various screen configurations, the
app uses layout aliases to match them to each configuration:
所以每种布局是一个XML文件中定义在res /layout/
directory目录下。然后将每个布局分配给各种屏幕配置,应用程序使用布局别名匹配他们每个配置:
res/layout/onepane.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
res/layout/onepane_with_bar.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:id="@+id/linearLayout1" android:gravity="center" android:layout_height="50dp"> <ImageView android:id="@+id/imageView1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/logo" android:paddingRight="30dp" android:layout_gravity="left" android:layout_weight="0" /> <View android:layout_height="wrap_content" android:id="@+id/view1" android:layout_width="wrap_content" android:layout_weight="1" /> <Button android:id="@+id/categorybutton" android:background="@drawable/button_bg" android:layout_height="match_parent" android:layout_weight="0" android:layout_width="120dp" style="@style/CategoryButtonStyle"/> </LinearLayout> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="match_parent" /> </LinearLayout>
res/layout/twopanes.xml
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="400dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent" /> </LinearLayout>
res/layout/twopanes_narrow.xml
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="200dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent" /> </LinearLayout>
Now that all possible layouts are defined, it‘s just a matter of mapping the correct layout to each configuration using the configuration qualifiers. You can now do it using the layout alias technique:
现在所有可能的布局定义,它只是一种映射正确的布局配置使用配置限定符。你现在可以做到使用别名技术布局:
res/values/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/onepane_with_bar</item> <bool name="has_two_panes">false</bool> </resources>
res/values-sw600dp-land/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/twopanes</item> <bool name="has_two_panes">true</bool> </resources>
res/values-sw600dp-port/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/onepane</item> <bool name="has_two_panes">false</bool> </resources>
res/values-large-land/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/twopanes</item> <bool name="has_two_panes">true</bool> </resources>
res/values-large-port/layouts.xml
:
<resources> <item name="main_layout" type="layout">@layout/twopanes_narrow</item> <bool name="has_two_panes">true</bool> </resources>
Use Nine-patch Bitmaps 使用Nine-patch位图
Supporting different screen sizes usually means that your image resources must also be capable of adapting to different sizes. For example, a button background must fit whichever button shape it is applied to.
支持不同的屏幕尺寸通常意味着您的图像资源也必须能够适应不同大小。例如,一个按钮背景必须适合哪个按钮形状。
If you use simple images on components that can change size, you will quickly notice that the results are somewhat less than impressive, since the runtime will stretch or shrink your images uniformly. The solution is using nine-patch bitmaps, which are specially
formatted PNG files that indicate which areas can and cannot be stretched.
如果你使用简单的图像组件,可以改变大小,你很快就会注意到有些令人印象深刻的结果,因为运行时将伸展或收缩你的照片一致,解决方案是使用nine-patch位图,这是特殊格式化的PNG文件表明哪些领域可不可以被拉伸。
Therefore, when designing bitmaps that will be used on components with variable size, always use nine-patches. To convert a bitmap into a nine-patch, you can start with a regular image (figure 4, shown with in 4x zoom for clarity).
因此,设计位图在组件使用的变量的大小,总是使用nine-patches。将位图转换成nine-patch,您可以从一个常规的图像(图4中,显示在4倍变焦清晰)。
Figure 4. button.png
And then run it through the draw9patch
utility of the SDK (which is located in the tools/
directory),
in which you can mark the areas that should be stretched by drawing pixels along the left and top borders. You can also mark the area that should hold the content by drawing pixels along the right and bottom borders, resulting in figure 5.
然后运行它通过SDK的draw9patch效用(位于 tools/
directory),您可以在其中标记应该延伸的区域沿着左边和顶部边界画像素。你也可以标记有内容的区域沿着右边和底部边界画像素,结果在图5中。
Figure 5. button.9.png
Notice the black pixels along the borders. The ones on the top and left borders indicate the places where the image can be stretched, and the ones on the right and bottom borders indicate where the content should be placed.
注意沿着黑色像素边界。顶部和左边界表示的图像可以被拉伸的地方,和右边和底部边界的显示内容应该放置的地方。
Also, notice the .9.png
extension. You must use this extension, since this is how the framework detects that this is a nine-patch image, as opposed
to a regular PNG image.
注意.9.png扩展。你必须使用这个扩展,这是框架能够检测是nine-patch图片,而不是一个常规的PNG图片。
When you apply this background to a component (by setting android:background="@drawable/button"
), the framework stretches the image correctly to accommodate
the size of the button, as shown in various sizes in figure 6.
当你请求这个背景组件(settingandroid:背景=“@drawable /按钮”),该框架延伸图像正确适应按钮的大小,如各种大小,如图6所示。
Figure 6. A button using the button.9.png
nine-patch in various sizes.
图6。一个按钮使用button.9.png nine-patch不同尺寸。