在这里插入图片描述

1 -> 引言

随着鸿蒙生态向PC、2in1设备以及平板自由多窗模式的持续演进,应用在多窗口场景下的交互体验变得愈发重要。鸿蒙6.0(API Version 20)在窗口管理模块中,针对这些设备形态进行了三项关键的能力增强,旨在提升多窗口场景下的视觉一致性、交互逻辑与沉浸感。

本文将从实际开发角度,深入解析 setRelativePositionToParentWindowEnabledsetWindowShadowEnabled 以及 setWindowContainerColor 这三个新增接口的背景、使用场景与实现细节。

2 -> 能力增强背景与概述

在传统的手机和平板场景中,窗口通常以全屏或简单分屏形式存在。而在PC、2in1设备以及支持自由多窗模式的平板设备上,窗口行为更接近于桌面操作系统:用户可以自由调整窗口位置、大小,且多个窗口可以层叠、切换焦点。

这种复杂的窗口管理模式对应用提出了新的挑战:

  1. 相对位置关联:当主窗口移动时,其附属的子窗口(如工具面板、弹窗)应如何跟随?如果不跟随,会导致视觉分离,破坏用户心智模型。
  2. 视觉反馈与层次:在没有窗口阴影的情况下,多个重叠窗口的层次关系难以区分,用户难以判断当前焦点窗口。
  3. 焦点态与非焦点态的区分:传统的仅靠标题栏高亮来区分焦点状态,在多窗口密集排布时不够醒目,开发者需要更细粒度的控制来增强窗口容器的视觉反馈。

针对上述痛点,鸿蒙6.0在 Window 类中引入了三个新的同步方法(标记为20+),专门用于增强这些设备上的窗口管理能力。

3 -> 核心能力详解与代码实践

3.1 -> 相对位置锁定:setRelativePositionToParentWindowEnabled

功能说明

该接口用于设置一级子窗口是否保持与主窗口的相对位置不变。在PC或平板的多窗口模式下,当一个主窗口被拖拽移动时,其创建的子窗口(例如悬浮工具栏、颜色选择器或辅助面板)通常会希望跟随主窗口一起移动,以保持应用界面的整体性。

如果未启用此功能,移动主窗口时,子窗口会停留在原来的屏幕位置,导致主窗口与子窗口分离,用户体验割裂。启用后,子窗口将相对于主窗口的位置保持不变,仿佛“附着”在主窗口上。

API 详解

setRelativePositionToParentWindowEnabled(enabled: boolean): void
  • 参数:
    • enabled: true 表示启用一级子窗口与主窗口的相对位置保持功能;false 表示禁用。
  • 系统能力: SystemCapability.Window.SessionManager
  • 使用限制:
    • 此接口在2in1设备中可正常调用,在其他设备上调用会返回错误码801(Capability not supported)。
    • 仅适用于一级子窗口。这意味着只有通过主窗口(Main Window)创建的直接子窗口(SubWindow)会受到影响。

代码示例

以下示例展示如何创建一个子窗口,并启用其跟随主窗口移动的功能。

// EntryAbility.ets
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // 加载主窗口内容
    windowStage.loadContent('pages/Index', (err: BusinessError) => {
      if (err.code) {
        console.error(`Failed to load main content. Code: ${err.code}`);
        return;
      }
      console.info('Main window loaded.');

      // 创建并配置子窗口
      windowStage.createSubWindow('myToolWindow')
        .then((subWindow: window.Window) => {
          // 设置子窗口内容
          subWindow.setUIContent('pages/ToolPanel', (err: BusinessError) => {
            if (err.code) {
              console.error(`Failed to load sub content. Code: ${err.code}`);
              return;
            }
            console.info('Sub window content loaded.');

            // 核心:启用子窗口相对于主窗口的相对位置保持功能
            // 需要确保该接口仅在支持的设备上调用,可以通过 canIUse 进行判断
            if (canIUse('SystemCapability.Window.SessionManager')) {
              try {
                subWindow.setRelativePositionToParentWindowEnabled(true);
                console.info('Relative position lock enabled for sub window.');
              } catch (exception) {
                console.error(`Failed to set relative position: ${exception.message}`);
              }
            }

            // 设置子窗口的初始位置和大小(相对于主窗口的偏移)
            // 注意:此位置在移动主窗口后,会保持相对距离不变
            subWindow.moveWindowTo(100, 100);
            subWindow.resize(300, 200);
            // 显示子窗口
            subWindow.showWindow();
          });
        })
        .catch((err: BusinessError) => {
          console.error(`Failed to create sub window: ${err.message}`);
        });
    });
  }
}

3.2 -> 窗口视觉层次:setWindowShadowEnabled

功能说明

在桌面操作系统中,阴影是区分窗口层级和增加视觉深度的关键元素。该接口用于设置主窗口是否显示阴影。

当有多个窗口层叠时,阴影能够帮助用户清晰辨别哪个窗口位于最顶层(通常阴影更深),以及窗口之间的相对前后关系。这对于自由多窗模式下的用户体验至关重要。

API 详解

setWindowShadowEnabled(enabled: boolean): void
  • 参数:
    • enabled: true 表示显示窗口阴影;false 表示不显示。
  • 系统能力: SystemCapability.Window.SessionManager
  • 使用限制:
    • 该接口仅在2in1设备中可正常调用,在其他设备上调用会返回错误码801。
    • 该接口作用于主窗口,不适用于子窗口或其他类型窗口。

代码示例

以下示例展示如何在应用主窗口加载完成后,启用窗口阴影。

// EntryAbility.ets
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // 加载主窗口内容
    windowStage.loadContent('pages/Index', (err: BusinessError) => {
      if (err.code) {
        console.error(`Failed to load main content. Code: ${err.code}`);
        return;
      }
      console.info('Main window loaded.');

      // 获取主窗口实例
      windowStage.getMainWindow((err: BusinessError, mainWindow: window.Window) => {
        if (err.code) {
          console.error(`Failed to get main window: ${err.message}`);
          return;
        }

        // 启用主窗口阴影
        if (canIUse('SystemCapability.Window.SessionManager')) {
          try {
            mainWindow.setWindowShadowEnabled(true);
            console.info('Window shadow enabled.');
          } catch (exception) {
            console.error(`Failed to enable window shadow: ${exception.message}`);
          }
        }
      });
    });
  }
}

3.3 -> 焦点与非焦点容器背景色:setWindowContainerColor

功能说明

该接口允许开发者单独设置主窗口容器在焦点态(获得焦点)和非焦点态(失去焦点)时的背景色。这是增强窗口交互反馈最直接的方式。

值得注意的是,窗口容器背景色覆盖整个窗口区域,包括标题栏和内容区域。这为开发者提供了比单纯修改标题栏颜色更强大的视觉定制能力。当同时使用 setWindowContainerColorsetWindowBackgroundColor 时,内容区域会显示后者(窗口背景色),而标题栏会显示前者(窗口容器背景色),从而形成层次分明的视觉效果。

API 详解

setWindowContainerColor(activeColor: string, inactiveColor: string): void
  • 参数:
    • activeColor: 窗口获得焦点时的容器背景色,支持十六进制RGB或ARGB格式(例如 '#00FF00''#FF00FF00')。
    • inactiveColor: 窗口失去焦点时的容器背景色,同样支持RGB或ARGB格式。
  • 系统能力: SystemCapability.Window.SessionManager
  • 权限要求: ohos.permission.SET_WINDOW_TRANSPARENT
  • 使用限制:
    • 必须在 loadContent()setUIContent() 方法之后调用。
    • 仅在2in1设备上正常生效。

代码示例

以下示例展示如何为应用主窗口设置焦点态为半透明,非焦点态为深色半透明背景。

// EntryAbility.ets
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/Index', (err: BusinessError) => {
      if (err.code) {
        console.error(`Failed to load main content. Code: ${err.code}`);
        return;
      }
      console.info('Main window loaded.');

      windowStage.getMainWindow((err: BusinessError, mainWindow: window.Window) => {
        if (err.code) {
          console.error(`Failed to get main window: ${err.message}`);
          return;
        }

        // 设置窗口容器焦点态与非焦点态背景色
        // 需要确保已声明 ohos.permission.SET_WINDOW_TRANSPARENT 权限
        if (canIUse('SystemCapability.Window.SessionManager')) {
          try {
            // 焦点态:全透明 (ARGB)
            const activeColor = '#00000000';
            // 非焦点态:黑色,半透明 (ARGB)
            const inactiveColor = '#CC000000';
            mainWindow.setWindowContainerColor(activeColor, inactiveColor);
            console.info('Window container color set successfully.');
          } catch (exception) {
            console.error(`Failed to set window container color: ${exception.message}`);
          }
        }
      });
    });
  }
}

权限配置(module.json5)

使用此接口前,需在 module.json5 文件中申请权限:

{
  "module": {
    // ...
    "requestPermissions": [
      {
        "name": "ohos.permission.SET_WINDOW_TRANSPARENT"
      }
    ]
  }
}

4 -> 总结与最佳实践

鸿蒙6.0 在窗口管理方面的这三项增强,并非简单的功能堆砌,而是对多窗口交互模型的深刻理解与优化。它们共同解决了在类桌面环境下,窗口之间如何协调、如何呈现、如何反馈的核心问题。

  1. 关于 setRelativePositionToParentWindowEnabled

    • 适用场景:任何需要“附着”于主窗口的工具面板、辅助面板、快捷菜单等。启用后,开发者无需在主窗口移动事件中手动计算并移动所有子窗口,极大地简化了多窗口联动逻辑。
    • 注意:它仅作用于一级子窗口。如果你的应用存在嵌套子窗口(子窗口再创建子窗口),需要评估其逻辑层级关系。
  2. 关于 setWindowShadowEnabled

    • 适用场景:所有在自由多窗模式下运行的应用。阴影是视觉语言中非常重要的元素,建议在PC或2in1设备上默认启用,以符合用户对桌面应用的预期。
    • 注意:阴影的样式(大小、模糊度)由系统统一控制,当前版本不支持自定义阴影参数。开发者只需控制其开启或关闭即可。
  3. 关于 setWindowContainerColor

    • 适用场景:需要对窗口焦点状态进行强视觉反馈的应用。特别是当应用采用全透明或沉浸式标题栏设计时,通过改变整个窗口容器的背景色,能更清晰地向用户指示当前可操作的窗口。
    • 最佳实践
      • 焦点态与非焦点态的配色应具有明显对比,但非焦点态不宜过于抢眼,以免分散用户注意力。
      • setWindowBackgroundColor 配合使用,可以创造出内容区稳定、标题栏随焦点变化的微妙效果。
      • 由于需要特定权限,请在申请权限时向用户清晰说明用途,避免引起隐私担忧。

开发建议

  • 设备兼容性判断:由于这三项接口仅在特定设备(PC/2in1)上生效,务必在调用前使用 canIUse 接口进行判断,或者根据设备类型动态调用,避免在手机等不支持设备上引发801错误。
  • 调用时机setWindowContainerColor 必须在 loadContent 之后调用;而其他两个接口相对灵活,但建议在窗口创建后、显示前完成设置,避免视觉闪烁。
  • 联合使用:这三项能力可以协同工作。例如,为一个2in1设备的绘图应用创建浮动工具面板(使用相对位置锁定),同时为主窗口增加阴影(增强层次),并配置焦点态背景色(明确交互区域),共同打造出一流的桌面级应用体验。

随着鸿蒙在多设备领域的持续深耕,这种针对特定形态窗口能力的精细化增强,将帮助开发者构建出更专业、更符合用户直觉的应用,真正实现“一次开发,多端部署”的终极愿景。


感谢各位大佬支持!!!

互三啦!!!
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐