6.实现针对具体场景的布局

6.1 问题

应用必须是通用的,能在各种尺寸和方向的屏幕上运行。你需要为各种不同的情况准备好相应的布局资源。

6.2解决方案

(API Level 4)
构建多个布局文件,然后通过资源限定符让Android选择合适的布局。下面看看如何使用资源构建特定于不同的大小和方向屏幕的布局,还可以学习在多个配置使用同一布局时如何使用布局别名来减少重复代码。

6.3 实现机制

1.针对不同方向

用下面的限定符可以为Activity的横屏和竖屏方向创建不同的资源:
- resource-land
- resource-port
这适用于所有类型的资源,但通常都是用于布局。因此,在项目中不能只有res/layout/一个目录,而是应该有res/layout-port和res/layout-land/两个目录。
注意:
在实际开发中最好有一个不带标识符的默认资源目录。这样在Android设备不能匹配任何给定的设置时也能有可用的资源。

2.针对不同尺寸

屏幕尺寸标识符(物理尺寸,不要与像素密度混淆)可以用于针对平板电脑等大屏幕设备的资源。大部分情况下,一个布局就能满足所有手机设备的屏幕尺寸,但如果在平板电脑上,就可能需要专门的平板电脑布局来填充用户所面对的大屏幕。
在Android 3.2 (API Level 13)之前,下面的资源标识符用于标识屏幕的物理尺寸:

  • resource-small : 屏幕尺寸最小为426dp*320dp
  • resource-medium : 屏幕尺寸最小为 470dp*320dp
  • resource-large : 屏幕尺寸最小为640dp*480dp
  • resource-xlarge : 屏幕尺寸最小为960dp”720dp
    随着手持设备和平板电脑中大屏幕设备越来越普及,显然只有4种广义的类型不能完成避免资源定义上的重叠。因此,在Android3.2中引入一个新的基于屏幕真实尺寸(单位为dp(density-independent pixels))的系统。通过这个新系统,可以对物理屏幕使用以下资源标识符 :

  • 最小宽度(resource-sw_dp): 屏幕在最短方向上(即方向无关)至少具有指定的dp。640dp*480dp的屏幕通常最小宽度为480dp。

  • 宽度(resource-w_dp):屏幕在当前水平方向上(即方向无关)至少具体指定的dp。640dp*480dp的屏幕横屏时宽度为640dp,而竖屏时宽度为480dp。
  • 高度(resource-h_dp): 屏幕在当前垂直方向上(即方向无关)至少具有指定的dp。640dp*480dp的屏幕竖屏时高度为640dp,而横屏时高度为480dp。
    所以,要想在整个应用程序中包含平板电脑专用的布局,只需要为旧版本的平板电脑添加/res/layout-large/目录,为新版本的平板电脑添加res/layout-sw720dp/目录即可。

3.布局别名

在创建通用的应用程序UI时,还有最后一个概念需要讨论,那就是布局的别名。通常同一个布局要用于多个不同的设备配置,但在同一个资源目录中使用多个资源限定符(如最小宽度限定符和传统的尺寸限定符)会产生问题。这种情况常常会导致开发人员要在不同的目录中创建同一个布局的多个副本,这维护起来非常困难。
我们可以通过别名解决这个问题。首先在默认资源目录中创建一个布局文件,然后就可以在以“资源-限定符”命名的目录下为这个文件创建多个别名。下面的代码片段演示了res/layout/main_tablet.xml文件的别名:

<resources>
    <item name="main" type="layout">@layout/main_tablet</item>
</resources>

name属性表示别名的名称,表示这个别名代表的资源会用在特定的配置上。当在代码中使用R.layout.main时,这个别名就会链接到main_tablet.xml文件。这段代码可以放到res/values-xlarge/layout.xml和res/values-sw720dp/layout.xml中,这样这两个配置都会链接到同一个布局。

4.综合示例

接下来看一个综合使用这些技术的简单示例。定义一个Activity,在其中用代码加载一个布局资源。不过,在该资源中这个布局被定义了三次,分别针对竖屏、横屏和平板电脑产生不同的结果。先看看以下代码中的Activity:
加载一个布局的简单Activity

public class UniversalActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

现在我们将为该Activity的不同配置定义三个单独的布局。以下三段代码显示了默认的布局、横屏时的布局和平板电脑配置的UI布局。
res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 默认布局 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="This is the default layout" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button One" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button Two" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button Three" />
</LinearLayout>

res/layout-land/main.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 横屏时的布局-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is a horizontal layout for LANDSCAPE" />
    <!-- 三个按钮会平均大小地填满整个屏幕-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button One" />
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button Two" />
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button Three" />
    </LinearLayout>
</LinearLayout>

res/layout/main_tablet.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 平板电脑的布局 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    <!-- 所有的用户按钮占用25%的屏幕宽度 -->
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="This is the layout for TABLETS" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button One" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button Two" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button Three" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button Four" />
    </LinearLayout>
    <!-- 显示详细内容的额外视图 -->
    <TextView 
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"
        android:text="Detail View"
        android:background="#CCC"/>
</LinearLayout>

一种方式是创建具有相同文件名的三个文件并把它们放到各自的配置目录中,例如用于横屏的res/layout-land目录和用于平板电脑的res/layout-large目录。如果每个布局文件只使用一次,这种方案是非常好的,但我们想要在多个配置下重用每个布局,因此在这个示例中采用了为这三个布局创建限定别名的方式。以下四段代码显示了如何将每个布局链接到正确的配置。
res/values-large-land/layout.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <item name="main" type="layout">@layout/main_tablet</item>
</resources>

res/value-sw600dp-land/layout.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <item name="main" type="layout">@layout/main_tablet</item>
</resources>

res/values-xlarge/layout.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <item name="main" type="layout">@layout/main_tablet</item>
</resources>

res/values-sw720dp/layout.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <item name="main" type="layout">@layout/main_tablet</item>
</resources>

我们定义了一组配置来适应三种类型的设备:手机/7英寸平板设备/10英寸平板设备。手机设备会在竖屏模式时加载默认的布局,在屏幕旋转时加载横屏布局。因此只有只有一种配置使用这些文件,所以文件会被直接分别放置到res/layout和res/layout-land目录下。
7英寸的平板设备在之前的尺寸方案中通常会被定义为超大屏幕设备,而在新的方案中它们是最小宽度为大约600dp的设备。竖屏时,我们决定让应用程序都使用默认的布局,而在横屏时会得到更大的空间,因此我们改为加载平板电脑的布局。要想实现该功能,我们为横屏模式创建多个配置目录来匹配设备的类型。同时使用了最小宽度限定符和广义的尺寸限定符,这样就可以兼容旧平板电脑和新平板电脑。
10英寸的平板设备在之前的尺寸方案中通常会被定义为超大屏幕设备,而在新的方案中它们是最小宽度为大约720dp的设备。对于这些设备,屏幕大到可以在两个方向都使用平板电脑布局,因此只通过屏幕尺寸定义了配置目录。和小平板电脑一样,同时使用最小宽度和广义尺寸限定符来保证可以兼容所有的平板电脑版本。
在所有引用平板电脑布局的场景中,我们只需要创建一个布局文件即可管理,这多亏使用了别名。现在,运行应用程序后,会看到Android是如何让选择合适的布局来匹配我们的配置的。下图显示了手机上默认的布局和横屏时的布局。
手机上竖屏时的布局
手机上横屏时的布局
同样的应用程序运行在7英寸的平板设备上会在竖屏时显示默认的布局,但在横屏上会显示全屏的平板电脑布局。在更大的10英寸上横屏和竖屏都会显示全屏的平板电脑布局。通过Android资源选择系统的强大能力,大大减少了为不同设备类型提供不同的优化UI布局的难度。

猜你喜欢

转载自blog.csdn.net/qq_41121204/article/details/82587700
今日推荐