学习 Android XR 基础知识:第 1 部分 - 模式和空间面板

1. 准备工作

学习内容

  • XR 设备类型能够提供的独特用户体验。
  • 学习如何通过使用 Jetpack Compose XR 库提供的可组合项,调整应用以充分利用在 Android XR 头戴式设备上运行的优势。
  • 如何使用 Compose XR 库提供的界面元素。
  • 详细了解如何构建适用于 Android XR 的应用。

这并非是

所需条件

构建内容

在此 Codelab 中,您将通过 Android XR 增强基本单屏应用,提供身临其境的用户体验。

起始代码

最终结果

2. 进行设置

获取代码

  1. 此 Codelab 的代码可以在 xr-codelabs GitHub 存储库的 xr-fundamentals 目录中找到。如需克隆此代码库,请运行以下命令:
git clone https://github.com/android/xr-codelabs.git
  1. 或者,您也可以下载代码库 Zip 文件。

打开项目

  • 在启动 Android Studio 后,导入项目,仅选择 xr-fundamentals/start 目录。xr-fundamentals/part1 目录包含解决方案代码,如果您遇到困难或只想查看完整项目,可以随时参考。

熟悉代码

  • 在 Android Studio 中打开项目后,花些时间浏览起始代码。

3. 了解 XR 概念:模式和空间面板

在此 Codelab 中,您将学习两个 Android XR 概念:模式和空间面板。您还将了解如何将这些概念应用于在 Android XR 设备上运行的应用。

Modes

在 Android XR 设备上,应用会在以下两种模式之一中运行:Home Space模式或 Full Space 模式。

Home Space 模式

d779257a53898d36.jpeg

在 Home Space 模式下,多个应用可以并排运行,以便用户在多个应用之间同时处理多个任务。Android 应用可以在不进行修改的情况下在 Home Space 模式下运行。

Full Space 模式

c572cdee69669a23.jpeg

在 Full Space 模式下,一次只运行一个应用,且没有空间边界。所有其他应用都会被隐藏。应用必须执行额外的工作才能进入 Full Space 模式,并利用此模式中可用的其他功能。

如需详细了解这些模式,请参阅 Home Space 模式和 Full Space 模式

空间面板

空间面板是容器元素,是 Android XR 应用的基本构建块。

在 Home Space 模式中运行时,您的应用将包含在单个面板中,提供类似于大屏 Android 设备上的窗口化模式的体验。

在 Full Space 模式下运行时,您可以将应用的内容拆分到一个或多个面板中,以提供更具沉浸感的体验。

如需详细了解面板,请参阅空间面板

4. 在 Android XR 模拟器中运行应用

在开始针对 Android XR 优化应用之前,您可以在 Android XR 模拟器中运行应用,查看其在 Home Space 模式下的外观。

安装 Android XR 系统映像

  1. 首先,在 Android Studio 中打开 SDK 管理器,然后选择 SDK Platforms 标签页(如果尚未选择)。在 SDK 管理器窗口的右下角,确保选中 Show package details 复选框。
  2. 在 Android 14 部分下,安装 Android XR ARM 64 v8a 或 Android XR Intel x86_64 模拟器映像。映像只能在具有与其相同架构 (x86/ARM) 的机器上运行。

创建 Android XR 虚拟设备

  1. 打开设备管理器后,选择窗口左侧 Category 列下的 Automotive。然后,从列表中选择 XR Device 硬件配置文件,然后点击 Next

7a5f6b9c1766d837.png

  1. 在下一页上,选择您之前安装的系统映像。点击 Next,并选择所需的任何高级选项,最后点击 Finish 以创建 AVD。
  2. 在您刚刚创建的 AVD 上运行应用。

7cf6569ef7967d87.png

5. 设置依赖项

在开始向应用添加 XR 专用功能之前,您需要添加对 Jetpack Compose for XR 库 androidx.xr.compose:compose 的依赖项,该库包含为应用构建 Android XR 优化体验所需的所有可组合项。

libs.version.toml

[versions]
...
xrCompose = "1.0.0-alpha01"

[libraries]
...
androidx-xr-compose = { group = "androidx.xr.compose", name = "compose", version.ref = "xrCompose" }

build.gradle.kts(模块 :app)

dependencies {
    ...
    implementation(libs.androidx.xr.compose)
    ...
}

更新这些文件后,请务必执行 Gradle 同步,以确保依赖项已下载到您的项目中。

6. 进入 Full Space 模式

如需使用面板等 XR 功能,应用必须在 Full Space 模式下运行。应用可以通过以下两种方式进入 Full Space 模式:

  • 以程序化方式,例如响应应用中的用户互动
  • 在启动时立即执行,方法是向应用清单添加指令。

以程序化方式进入 Full Space 模式

如需以程序化方式进入 Full Space 模式,您可以在界面中提供相应功能,让用户控制他们希望在哪种模式下使用应用。此外,您还可以根据应用使用情境进入 Full Space 模式。例如,在开始观看视频内容时进入 Full Space 模式,在播放完毕后退出 Full Space 模式。

为简单起见,您可以先在顶部应用栏中添加一个按钮来切换模式。

  1. com.example.android.xrfundamentals.ui.component 软件包中创建一个新文件 ToggleSpaceModeButton.kt,并添加以下可组合项:

ToggleSpaceModeButton.kt

package com.example.android.xrfundamentals.ui.component

import androidx.annotation.DrawableRes
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.xr.compose.platform.LocalSpatialCapabilities
import androidx.xr.compose.platform.LocalSpatialConfiguration
import com.example.android.xrfundamentals.R
import com.example.android.xrfundamentals.ui.theme.XRFundamentalsTheme

@Composable
fun ToggleSpaceModeButton(modifier: Modifier = Modifier) {
    val spatialConfiguration = LocalSpatialConfiguration.current

    if (LocalSpatialCapabilities.current.isSpatialUiEnabled) {
        ToggleSpaceModeButton(
            modifier = modifier,
            contentDescription = "Request Home Space mode",
            iconResource = R.drawable.ic_home_space_mode,
            onClick = { spatialConfiguration.requestHomeSpaceMode() }
        )
    } else {
        ToggleSpaceModeButton(
            modifier = modifier,
            contentDescription = "Request Full Space mode",
            iconResource = R.drawable.ic_full_space_mode,
            onClick = { spatialConfiguration.requestFullSpaceMode() }
        )
    }
}

@Composable
fun ToggleSpaceModeButton(
    contentDescription: String,
    @DrawableRes iconResource: Int,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    IconButton(
        modifier = modifier,
        onClick = onClick
    ) {
        Icon(
            painterResource(iconResource),
            contentDescription
        )
    }
}
  1. 在应用在 XR 设备上运行时,将该按钮添加为 TopAppBar 中的操作

XRFundamentalsTopAppBar.kt

import androidx.xr.compose.platform.LocalHasXrSpatialFeature

...

TopAppBar(
    ...,
    actions = {
        // Only show the mode toggle if the device supports spatial UI
        if (LocalHasXrSpatialFeature.current) {
            ToggleSpaceModeButton()
        }
    }
)

现在运行应用。

应用在启动时在 Home Space 模式下运行。点按面板右上角的按钮,切换到 Full Space 模式。

应用在 Full Space 模式下运行。请注意,用于最小化/关闭应用的系统界面已消失。点按面板右上角的按钮,切换回 Home Space 模式。

这些代码段包含一些值得注意的新 API:

  • LocalSpatialConfiguration 是一个本地组合,可提供对应用当前空间配置的访问权限。除了用于请求更改模式的方法之外,它还包含其他信息,例如包含应用的卷的大小。
  • LocalSpatialCapabilities 是一个本地组合,可用于确定应用当前可使用的空间功能。除了模式(Home Space 或 Full Space)之外,还包括空间音频和 3D 内容支持等功能。
  • LocalHasXrSpatialFeature 是一个本地组合,可用于确定应用是否在支持空间界面功能的设备上运行。在后台,它会检查设备是否具有 android.software.xr.immersive 系统功能

在启动时进入 Full Space 模式

如需指示操作系统以 Full Space 模式启动 activity,您可以在相应的 <activity> 元素中添加具有以下属性的 <property> 元素。只有在用户不太可能在使用您的应用的同时使用其他应用时,我们才建议您使用这种方式。

AndroidManifest.xml

<activity
    android:name=".MainActivity" 
    ... >
    <property
        android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE"
        android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED" />
</activity>

现在,当应用启动时,用户会立即进入 Full Space 模式。

abbf3d27cd2a4532.gif

在继续操作之前,请从清单中移除上述 <property> 元素,以便应用使用默认行为,即在 Home Space 模式下打开。

7. 将界面拆分为多个面板

现在,您的应用可以进入和退出 Full Space 模式,是时候更好地利用它了。一种很好的方法是,将应用的内容拆分为多个面板以填充空间,并(可选)允许用户根据需要移动和调整这些面板的大小。

将应用嵌入子空间

首先,在 XRFundamentalsApp 可组合项中的 Scaffold 可组合项后面添加一个 Subspace 可组合项。子空间是应用中 3D 空间的一部分,您可以在其中构建 3D 布局(例如添加空间面板)、放置 3D 模型,以及为原本的 2D 内容添加深度。

在非 XR 设备上运行时,Subspace 可组合项的内容永远不会进入组合。在 XR 设备上运行时,只有在应用以 Full Space 模式运行时,内容才会进入组合。

XRFundamentalsApp.kt

import androidx.xr.compose.spatial.Subspace

...

HelloAndroidXRTheme {
    Scaffold(...)
    Subspace {
    }
}

现在,运行应用:

2d47561a616f4a11.gif

如果您的应用包含 Subspace 可组合项,系统会显示该可组合项,而不是 2D 内容。这意味着,当您点击该按钮进入 Full Space 模式时,系统不会再显示任何内容。为了解决此问题,您将在接下来的几个步骤中添加两个空间面板,一个用于包含主要内容,另一个用于包含次要内容。

为主要内容添加面板

如需在 Full Space 模式下显示主要内容,请在 Subspace 可组合项中添加 SpatialPanel

由于这是应用的主要面板,因此您可以在其中添加 Scaffold,以保持顶部应用栏中的控件处于显示状态。在下一个 Codelab 中,您将了解轨道器,轨道器可用于对应用栏中通常包含的控件(例如导航和特定于上下文的操作)进行空间化处理。

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.SpatialPanel

...

Subspace {
    SpatialPanel() {
        Scaffold(
            topBar = { XRFundamentalsTopAppBar() }
        ) { innerPadding ->
            Box(Modifier.padding(innerPadding)) {
                PrimaryCard(
                    modifier = Modifier
                        .padding(16.dp)
                        .verticalScroll(rememberScrollState())
                )
            }
        }
    }
}

再次运行应用,您会看到包含主要内容的 SpatialPanel 在 Full Space 模式下可见,但非常小。

89152c1991d422d4.gif

修改主要面板

为了让主面板更易于使用,您可以通过提供 SubspaceModifier 来增大主面板。子空间修饰符类似于修饰符,用于修饰面板等空间组件。

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.layout.SubspaceModifier
import androidx.xr.compose.subspace.layout.height
import androidx.xr.compose.subspace.layout.width
import androidx.compose.ui.unit.dp

...

SpatialPanel(
    modifier = SubspaceModifier
        .width(1024.dp)
        .height(800.dp)
){
    ...
}

再次运行应用,主面板应该会占用更多空间。

c4f28838e16a3eb8.gif

为次要内容添加面板

现在,您已经让应用在 Full Space 模式下运行,并使用面板来显示主要内容,接下来可以将次要内容移到自己的面板中了。请注意,在空间面板中使用 Surface。如果没有该 Surface,次要卡片将没有背景,因为空间面板本身是透明的(Scaffold 可组合项在前一步中处理了此问题)。

XRFundamentalsApp.kt

Subspace {
    SpatialPanel() { ... }
    SpatialPanel(
        modifier = SubspaceModifier
            .width(340.dp)
            .height(800.dp)
    ) {
        Surface {
            SecondaryCardList(
                modifier = Modifier
                    .padding(16.dp)
                    .verticalScroll(rememberScrollState())
            )
        }
    }
}

现在,再次运行应用。乍一看,第二个面板似乎没有显示,但实际上它是显示的,只是隐藏在主面板后面。

7db3c3428b64e482.gif

将面板排成一行

与 2D 内容一样,使用行和列有助于并排排列可组合项,而不会出现重叠。使用面板等空间组件时,您可以使用 SpatialRowSpatialColumn 可组合项来实现此目的。

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.SpatialRow

...

Subspace {
    SpatialRow(
        curveRadius = 825.dp
    ) {
        SpatialPanel(...) { ... }
        SpatialPanel(...) { ... }
    }
}

再次运行应用,您应该会看到面板依次排列成一行。此外,由于向 SpatialRow 提供 curveRadius,因此面板会围绕用户弯曲,而不是停留在同一平面上,从而提供更全面的体验。

7455811775088baf.gif

使面板可调整大小

为了让用户能够控制应用的外观,您可以使用 resizable 子空间修饰符让面板可调整大小。

默认情况下,可调整大小的面板可以缩小到零或无限扩展,因此您可能需要花时间根据面板将包含的内容设置适当的 minimumSizemaximumSize 参数。

如需详细了解 resizable 修饰符支持的所有参数,请参阅参考文档

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.layout.resizable

...

SpatialPanel(
    modifier = SubspaceModifier
        ...
        .resizable(true)
)

2ff2db33032fd251.gif

使面板可移动

同样,您可以使用 movable 子空间修饰符使面板可移动。

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.layout.movable

...

SpatialPanel(
    modifier = SubspaceModifier
        ...
        .movable(true)
)

12b6166645ea1be.gif

如需详细了解 movable 修饰符支持的所有参数,请参阅参考文档

8. 恭喜

如需继续了解如何充分利用 XR,请查看以下资源和练习。此外,您还可以申请参加 XR 训练营

深入阅读

挑战

  • 使用可用于 resizablemovable 子空间修饰符的其他参数。
  • 添加其他面板。
  • 使用其他空间组件,例如空间对话框

参考文档