窗口管理

ChromeOS 支持在多个窗口中使用 Android 应用。系统渲染应用 窗口容器的大小取决于 如图 1 所示。

图 1. 不同设备上的应用窗口。

设计适合不同屏幕尺寸的布局非常重要。如果您 遵循 Android 指南,支持不同的屏幕 尺寸,那么您的应用也能 在 Chrome 操作系统上运行时

此页面介绍了如何确保应用窗口正确启动和调整大小 并在其大小发生变化时显示所有内容。

初始启动大小

应用可以通过以下方式请求其初始启动大小:

  • 仅在桌面环境中使用启动大小。这有助于窗口管理器为您提供适当的边界和方向。如需在桌面模式下使用时指明偏好设置,请在 <activity> 内添加以下元标记:
<meta-data android:name="WindowManagerPreference:FreeformWindowSize"
           android:value="[phone|tablet|maximize]" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation"
           android:value="[portrait|landscape]" />
  • 使用静态启动边界。请在清单项的清单条目中使用 <layout> activity 来指定“固定”起始大小,如下例所示:
<layout android:defaultHeight="500dp"
            android:defaultWidth="600dp"
            android:gravity="top|end"
            android:minHeight="450dp"
            android:minWidth="300dp" />
  • 使用动态启动边界。创建新的 Activity 时,Activity 可以创建和使用 ActivityOptions.setLaunchBounds(Rect)。通过指定一个空矩形,您的应用可以最大化。

调整窗口大小

在 ChromeOS 中,用户可以按常规方式调整应用窗口的大小: 如图 2 所示。

图 2. 可调整大小的应用窗口。

使用 View 类:

  • 通过调用 onConfigurationChanged(..)。 例如,您可以将 android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" 添加到 activity 的清单中。如需详细了解如何处理配置变更,请参阅 处理配置变更
  • 让系统重启 Activity。在这种情况下,请 onSaveInstanceState,并使用 ViewModel 架构 组件来恢复之前的 保存状态。

使用 Jetpack Compose 时,大小调整行为取决于 activity 是如何配置的。如果以动态方式处理更改, 窗口大小发生变化时触发重组。如果 activity 处于 系统会在重启后进行初始组合。两者之一 务必要创建能够适应窗口变化的 Compose 布局 尺寸。不要假定固定尺寸。

窗口尺寸

让您的 activity 在每次启动时读取其窗口尺寸, 根据当前配置排列其内容。

如需确定当前配置,请对当前 Activity 调用 getResources().getConfiguration()。请勿使用 后台 Activity 或系统资源的配置。 后台 activity 没有大小,系统配置可能 包含多个具有冲突大小和方向的窗口, 可以提取数据。

请注意,窗口大小与屏幕大小不同。如需获取窗口大小(以 DP 为单位),请使用 Activity.getResources().getConfiguration().screenWidthActivity.getResources().getConfiguration().screenHeight。您或许永远都不需要使用屏幕大小。

内容边界

窗口的内容边界在调整大小后可能会发生变化。例如,如果窗口太大以致屏幕容纳不下,那么应用使用的窗口区域就可能会发生变化。请遵循以下准则:

  • 使用 Android 布局过程的应用会自动在可用空间中进行布局。
  • 原生应用需要读取可用区域并监控大小变化, 具有无法访问的界面元素您可以调用以下方法来确定相应界面的初始可用大小:

    • NativeActivity.mLastContent[X/Y/Width/Height]()
    • findViewById(android.R.id.content).get[Width/Height]()

    您可以使用观察器进行持续监控:

    • NativeActivity.onContentRectChangedNative()
    • NativeActivity.onGlobalLayout()
    • view.addOnLayoutChangeListener(findViewById(android.R.id.content)) 添加监听器

    如果应用预缩放其图片,请在每次分辨率发生变化时执行此操作。

自由式大小调整

ChromeOS 允许自由调整任何窗口的大小:用户可以更改窗口的 屏幕宽度、高度和位置。许多 Android 应用在编写时没有考虑到自由式大小调整。请考虑以下问题:

  • 屏幕位置可能会发生变化。请务必使用系统执行窗口到屏幕和屏幕到窗口坐标转换。
  • 如果您使用 Android 的视图系统,则当窗口大小发生变化时,窗口布局会自动发生变化。
  • 如果您不使用视图系统并接管界面,您的应用必须 会自动处理大小变化
  • 对于原生应用,请使用 mLastContent 成员或使用内容视图 确定初始大小。
  • 在应用运行时,监听 onContentRectChangedNativeonGlobalLayout 事件来响应大小变化。
  • 当应用的大小发生变化时,重新缩放或重新加载布局和海报图片 并更新输入区域。

全屏模式

全屏模式与原生 Android 上的工作方式相同。 如果窗口未覆盖整个屏幕,则请求全屏 (隐藏所有系统界面元素)会被忽略。当应用最大化时,会执行常规全屏方法、布局和功能。这样会隐藏系统界面元素(窗口控制栏和任务栏)。

屏幕方向

Android 应用最常见的屏幕方向是纵向,因为大多数用户都是这样拿手机的。虽然纵向很合适手机,但非常不适合笔记本电脑和平板电脑,因为这些设备通常是横向使用的。要获得 让您的应用呈现出最佳效果,请考虑支持这两种屏幕方向。

某些 Android 应用会假定,当设备处于竖屏模式时, 轮播值为 Surface.ROTATION_0。 对于大多数 Android 设备而言,可能确实如此。不过,当应用处于 确定 ARC 模式, 纵向的旋转值可能不是 Surface.ROTATION_0

为了在读取加速度计或类似传感器的读数时获得准确的旋转值,请使用 Display.getRotation() 方法并相应地交换轴。

根 Activity 和方向

一个 Chromebook 窗口由一堆 Activity 窗口组成。该堆栈中的每个窗口具有相同的大小和方向。

在桌面环境中,突然的方向和大小变化会让用户感到困惑。Chromebook 窗口管理器会通过类似的方式避免这种情况 Android 的并排模式:堆栈控件底部的 activity 其上所有 activity 的属性。这可能会导致意外情况 其中,新启动的纵向且不可调整大小的 activity 将变为横向 并可调整大小。

设备模式的作用如下:在平板电脑模式下,屏幕方向未锁定, 每个窗口都保留自己的方向,就像在 Android 上一样。

屏幕方向准则

处理屏幕方向时,请遵循以下准则:

  • 如果仅支持一种屏幕方向,请将该信息添加到清单中,以便窗口管理器在启动应用之前了解这一点。指定屏幕方向时,如有可能,还应指定传感器方向。Chromebook 通常是可翻转的,而上下颠倒的应用会带来糟糕的用户体验。
  • 尽量保持选定的一种屏幕方向。避免先在清单中请求一种屏幕方向,而后又以编程方式设置另一种屏幕方向。
  • 根据窗口大小改变屏幕方向时应格外小心。用户可能会 停留在较小的纵向窗口中,无法返回到较大的窗口 横向窗口。
  • Chrome 中有用于在所有可用布局之间切换的窗口控件。通过选择正确的屏幕方向选项,您可以确保用户 正确布局。如果应用支持纵向模式 和横向,请尽可能将其设置为横向。设置此选项后,系统会记住每个应用的相应设置。
  • 设法避免不必要的屏幕方向变化。例如,如果活动 屏幕方向为纵向,但应用调用 setRequestedOrientation(LANDSCAPE) 否则会导致不必要的窗口大小调整, 用户,并且可能会重启应用,但应用无法处理。最好设置一次屏幕方向(例如,在清单中设置),只有在必要时才进行更改。

其他注意事项

以下是在 Google Ads 中使用 Android 应用时需要考虑的 ChromeOS:

  • 不要在 Activity 的 onDestroy 方法中调用 finish()。这会导致 应用在调整大小时关闭而不是重启。
  • 不要使用不兼容的窗口类型,如 TYPE_KEYGUARDTYPE_APPLICATION_MEDIA
  • 通过缓存 之前分配的值
  • 如果您不希望用户调整应用的大小,请指定 android:resizeableActivity=false
  • 对您的应用进行测试,以确保其能够妥善处理窗口大小的变化。