包含 View 的响应式/自适应设计

无论屏幕尺寸如何,响应式/自适应布局都可以提供优化的用户体验。实现响应式/自适应布局,使基于视图的应用支持所有屏幕尺寸、屏幕方向和配置,包括可调整大小的配置,例如多窗口模式

自适应设计

如需支持各种设备外形规格,第一步是创建可适应应用可用显示空间量变化的布局。

ConstraintLayout

如需创建自适应布局,最佳方法是使用 ConstraintLayout 作为界面的基本布局。借助 ConstraintLayout,您可以根据布局中视图之间的空间关系指定每个视图的位置和大小。然后,所有视图都可以随着显示空间的变化一起移动和调整大小。

如需使用 ConstraintLayout 构建布局,最简单的方法是使用 Android Studio 中的布局编辑器。借助布局编辑器,您可以将新视图拖动到布局中,应用相对于父视图和同级视图的约束条件,以及设置视图属性,而无需手动修改任何 XML。

图 3. Android Studio 中的布局编辑器,显示了一个 ConstraintLayout

如需了解详情,请参阅使用 ConstraintLayout 构建自适应界面

自适应宽度和高度

为了确保您的布局能够适应不同的显示屏尺寸,请为视图组件的宽度和高度使用 wrap_contentmatch_parent0dp (match constraint),而不是硬编码的值:

  • wrap_content:视图设置其尺寸以适应视图包含的内容。
  • match_parent:视图在父视图中尽可能地展开。
  • 0dp (match constraint):在 ConstraintLayout 中,类似于 match_parent。视图会占用其约束范围内的所有可用空间。

例如:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/lorem_ipsum" />

图 4 显示了当显示宽度随设备屏幕方向的变化而变化时,TextView 的宽度和高度如何调整。

图 4. 一个自适应 TextView

TextView 将其宽度设置为填充所有可用空间 (match_parent),并将其高度设置为包含文本的高度 (wrap_content) 所需的空间,这使得视图能够适应不同的显示尺寸和不同量的文本。

如果您使用的是 LinearLayout,则还可以根据布局权重展开子视图,让视图按比例填充可用空间。但是,在嵌套的 LinearLayout 中使用权重将需要系统执行多次布局遍历以确定每个视图的大小,这会降低界面性能。

ConstraintLayout 几乎能够创建 LinearLayout 所能创建的所有布局,而不会影响性能,因此请将嵌套的 LinearLayout 转换为 ConstraintLayout。然后,您可以使用约束链定义加权布局

自适应设计

应用的布局应始终能适应不同的显示屏尺寸。不过,即使是自适应布局也无法在每台设备或多窗口模式显示屏上提供最佳用户体验。例如,您为手机设计的界面可能无法在平板电脑上提供最佳用户体验。自适应设计可提供针对不同显示屏尺寸进行了优化的备用布局。

对列表-详情界面使用 SlidingPaneLayout

列表-详情界面通常会在不同尺寸的屏幕上提供不同的用户体验。在大屏幕上,列表窗格和详情窗格通常并排显示。选择列表中的某一项后,项信息会显示在详情窗格中,而不会更改界面 - 两个窗格仍会并排显示。不过,在小屏幕上,两个窗格会分开显示,每个窗格都会占据整个显示区域。选择列表窗格中的某一项后,详情窗格(包含所选项的信息)会替换列表窗格。返回导航会将详情窗格替换为列表。

SlidingPaneLayout 用于管理用于确定这两种用户体验中的哪一种适合当前窗口大小的逻辑:

<?xml version="1.0" encoding="utf-8"?>
<androidx.slidingpanelayout.widget.SlidingPaneLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/item_navigation" />

</androidx.slidingpanelayout.widget.SlidingPaneLayout>

SlidingPaneLayout 中包含的两个视图的 layout_widthlayout_weight 属性决定了 SlidingPaneLayout 行为。在本例中,如果窗口足够大(宽度至少为 580dp)可以显示两个视图,则窗格会并排显示。但是,如果窗口宽度小于 580dp,窗格会相互叠加,以分别占据整个应用窗口。

如果窗口宽度大于指定的最小总宽度 (580dp),可以使用 layout_weight 值按比例调整两个窗格的大小。在本例中,列表窗格的宽度始终为 280dp,因为它没有权重。 不过,由于视图的 layout_weight 设置,详情窗格会始终填充超过 580dp 的所有水平空间。

备用布局资源

如需让界面设计适应变化很大的显示屏尺寸,请使用由资源限定符标识的备用布局。

图 5. 同一应用针对不同屏幕尺寸使用不同的布局。

您可以通过在应用的源代码中创建额外的 res/layout/ 目录来提供特定于屏幕的自适应布局。为需要不同布局的每个屏幕配置创建一个目录。然后,将屏幕配置限定符附加到 layout 目录名称(例如,对于可用宽度为 600dp 的屏幕,附加限定符为 layout-w600dp)。

配置限定符表示应用界面可用的可见显示空间。为应用选择布局时,系统会考虑所有系统装饰(例如导航栏)和窗口配置更改(例如多窗口模式)。

如需在 Android Studio 中创建备用布局,请参阅使用 View 开发界面中的使用布局变体针对不同的屏幕进行优化

“最小宽度”限定符

通过“最小宽度”屏幕尺寸限定符,您可以为具有最小宽度(以密度无关像素 (dp) 为单位)的屏幕提供备用布局。

通过将屏幕尺寸描述为 dp 的度量值,Android 使您能够创建针对特定显示屏尺寸设计的布局,而无需考虑不同的像素密度。

例如,您可以创建一个名为 main_activity 且针对手机和平板电脑进行了优化的布局,方法是在不同的目录中创建该文件的不同版本:

res/layout/main_activity.xml           # For phones (smaller than 600dp smallest width)
res/layout-sw600dp/main_activity.xml   # For 7" tablets (600dp wide or wider)

最小宽度限定符指定屏幕两侧的最小尺寸,而不考虑设备的当前屏幕方向,因此您可以通过它来指定布局可用的总体显示尺寸。

下面是其他最小宽度值与典型屏幕尺寸的对应关系:

  • 320dp:小手机屏幕(240x320 ldpi、320x480 mdpi、480x800 hdpi 等)
  • 480dp:约为 5 英寸的大手机屏幕 (480x800 mdpi)
  • 600dp:7 英寸平板电脑 (600x1024 mdpi)
  • 720dp:10 英寸平板电脑(720x1280 mdpi、800x1280 mdpi 等)

下图详细说明了不同屏幕 dp 宽度与不同屏幕尺寸和方向的对应关系。

图 6. 建议的宽度划分点,以支持不同的屏幕尺寸。

“最小宽度”限定符的值为 dp,因为重要的是系统考虑像素密度(而不是原始像素分辨率)之后可用的显示空间量。

您使用资源限定符(例如最小宽度)指定的尺寸不是实际屏幕尺寸,而是指定应用窗口可用的宽度或高度(以 dp 为单位)。Android 系统可能会将部分屏幕用于系统界面(如屏幕底部的系统栏或顶部的状态栏),因此部分屏幕可能不适用于您的布局。如果您的应用在多窗口模式下使用,则只能获取包含该应用的窗口的大小。调整窗口大小时,它会使用新的窗口大小触发配置更改,以便系统能够选择合适的布局文件。因此,您声明的资源限定符尺寸应仅指定应用所需的空间。在为布局提供空间时,系统会考虑系统界面使用的所有空间。

“可用宽度”限定符

您可能希望根据可用的宽度或高度来更改布局,而不是根据显示屏的最小宽度更改布局。例如,您可能希望在屏幕宽度至少为 600dp 时使用双窗格布局,但屏幕宽度可能会根据设备的屏幕方向是横向还是纵向而发生变化。在这种情况下,您应使用“可用宽度”限定符,如下所示:

res/layout/main_activity.xml         # For phones (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # For 7" tablets or any screen with 600dp available width
                                     # (possibly landscape phones)

如果您的应用需要考虑可用高度,您可以使用“可用高度”限定符。例如,对于屏幕高度至少为 600dp 的屏幕,请使用 layout-h600dp

“屏幕方向”限定符

尽管您可能只需组合使用“最小宽度”和“可用宽度”限定符即可支持所有尺寸变化,但您可能还需要改变用户在竖屏与横屏之间切换时的用户体验。

为此,您可以将 portland 限定符添加到布局目录名称中。只需确保屏幕方向限定符在尺寸限定符之后即可。例如:

res/layout/main_activity.xml                # For phones
res/layout-land/main_activity.xml           # For phones in landscape
res/layout-sw600dp/main_activity.xml        # For 7" tablets
res/layout-sw600dp-land/main_activity.xml   # For 7" tablets in landscape

如需详细了解所有屏幕配置限定符,请参阅应用资源概览

窗口大小类别

窗口大小类别是视口断点,可帮助您创建自适应布局。这些断点会将应用可用的显示区域标识为较小中等展开。宽度和高度是单独指定的,因此您的应用始终具有宽度的窗口大小类别和高度的窗口大小类别。

如需程序化地应用自适应布局,请执行以下操作:

如需详细了解窗口大小类别,请参阅支持不同的屏幕尺寸

使用 fragment 将界面组件模块化

在针对多种屏幕尺寸设计应用时,请使用 fragment 将界面逻辑提取到单独的组件中,以确保不会在 activity 之间不必要地复制界面行为。然后,您可以组合 fragment 以针对大屏设备创建多窗格布局,或者将 fragment 放置在小屏设备上的单独 activity 中。

例如,您可以使用一个包含列表的 fragment 和另一个包含列表项详情的 fragment,以实现“列表-详情”模式(请参阅上文的 SlidingPaneLayout)。在大屏幕上,fragment 可以并排显示;在小屏幕上,则会分别填满屏幕。

如需了解详情,请参阅 fragment 概览。

Activity 嵌入

如果您的应用由多个 activity 组成,activity 嵌入可让您轻松创建自适应界面。

activity 嵌入会在应用的任务窗口中同时显示多个 activity 或同一 activity 的多个实例。在大屏幕上,activity 可以并排显示;在小屏幕上,activity 可以堆叠显示。

您可以通过创建 XML 配置文件来确定应用如何显示其 activity,系统可以使用该文件根据显示屏尺寸确定适当的呈现方式。或者,您也可以进行 Jetpack WindowManager API 调用。

activity 嵌入支持设备屏幕方向的变化和可折叠设备,以及随着设备旋转或折叠和展开而堆叠和取消堆叠 activity。

如需了解详情,请参阅 activity 嵌入

屏幕尺寸和宽高比

针对各种屏幕尺寸和宽高比测试您的应用,以确保界面正确缩放。

Android 10(API 级别 29)及更高版本支持各种宽高比。可折叠设备的外形规格可能会有所不同,从高而窄的屏幕(例如折叠时的 21:9)到展开时的方形宽高比为 1:1 不等。

为了确保与尽可能多的设备兼容,请尽可能多地针对以下屏幕宽高比测试您的应用:

图 7. 各种屏幕宽高比。

如果您无法访问具有要测试的所有不同屏幕尺寸的设备,则可以使用 Android 模拟器模拟几乎所有屏幕尺寸。

如果您没有设备,但希望在真实设备上进行测试,则可以使用 Firebase Test Lab 访问 Google 数据中心内的设备。

其他资源