HarmonyOS Interface (WindowStage) 使用指南:从入门到实战

摘要: WindowStage 是 HarmonyOS 应用窗口管理的核心调度者,负责管理应用的生命周期、页面加载和多窗口协调。本文基于 HarmonyOS NEXT开发实践,系统讲解 WindowStage 接口的核心方法、生命周期回调和完整示例代码,帮助开发者掌握应用窗口阶段的控制能力。


效果

一、WindowStage 接口概述

WindowStage 代表应用的窗口阶段,是 UIAbility 与窗口系统之间的桥梁。每个 UIAbility 在 onWindowStageCreate 回调中接收一个 WindowStage 实例,通过它可以:

  • 加载应用页面内容
  • 获取主窗口实例
  • 创建应用子窗口
  • 监听窗口事件
  • 管理窗口布局与全屏模式

1.1 导入方式

import { window } from '@kit.ArkUI';

1.2 获取 WindowStage 实例

WindowStage 实例由系统在 UIAbility 生命周期中自动创建并传入,开发者无需手动创建:

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // 此处获取 windowStage 实例
  }
}

二、生命周期回调

2.1 onWindowStageCreate

当应用窗口阶段创建时触发,是初始化窗口和加载页面的关键入口

onWindowStageCreate(windowStage: window.WindowStage): void {
  hilog.info(0x0000, 'app', '窗口阶段已创建');

  // 1. 加载主页面
  windowStage.loadContent('pages/Index', (err) => {
    if (err.code) {
      hilog.error(0x0000, 'app', '加载失败: %{public}s', JSON.stringify(err));
      return;
    }
    hilog.info(0x0000, 'app', '页面加载成功');
  });
}

2.2 onWindowStageDestroy

当应用窗口阶段销毁时触发,用于释放窗口相关资源。

onWindowStageDestroy(): void {
  hilog.info(0x0000, 'app', '窗口阶段已销毁');
  // 清理资源
}

2.3 完整生命周期流程

UIAbility.onCreate()
    ↓
UIAbility.onWindowStageCreate(windowStage)  ← 窗口阶段创建
    ↓
  windowStage.loadContent('pages/Index')   ← 加载页面
    ↓
  页面 aboutToAppear() → build()           ← 页面渲染
    ↓
UIAbility.onForeground()                   ← 应用进入前台
    ↓
UIAbility.onBackground()                   ← 应用进入后台
    ↓
UIAbility.onWindowStageDestroy()           ← 窗口阶段销毁
    ↓
UIAbility.onDestroy()                      ← Ability销毁

三、核心方法详解

3.1 loadContent(path, callback)

加载应用主页面内容,是 onWindowStageCreate 中最核心的调用。

windowStage.loadContent('pages/Index', (err) => {
  if (err.code) {
    hilog.error(0x0000, 'app', '加载失败: %{public}s', JSON.stringify(err));
    return;
  }
  // 页面加载成功后的初始化操作
});

参数说明:

  • path:页面路由地址,对应 main_pages.json 中配置的页面路径
  • callback:加载完成回调,err.code 为 0 表示成功

重要提示: loadContent 必须在 getMainWindowSync() 等方法之前调用,或者在其回调中执行后续操作。

3.2 getMainWindowSync()

同步获取应用主窗口实例。

let mainWindow: window.Window = windowStage.getMainWindowSync();

获取主窗口后,可以进行以下操作:

// 获取UI上下文
let uiContext = mainWindow.getUIContext();

// 获取窗口属性
let props = mainWindow.getWindowProperties();
let windowId = props.id;

// 设置全屏
mainWindow.setWindowLayoutFullScreen(true);

// 获取避让区域
let avoidArea = mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);

3.3 createSubWindow(name, callback)

在当前窗口阶段创建应用子窗口。

windowStage.createSubWindow('mySubWindow', (err, subWindow) => {
  if (err.code) {
    hilog.error(0x0000, 'app', '创建子窗口失败: %{public}s', err.message);
    return;
  }
  // 子窗口创建成功,进行配置
  subWindow.setUIContent('subwindow/SubPage', () => {
    subWindow.setWindowBackgroundColor('#00000000');
  });
  subWindow.moveWindowTo(0, 300);
  subWindow.resize(200, 200);
  subWindow.showWindow();
});

参数说明:

  • name:子窗口名称,用于后续通过 window.findWindow(name) 查找
  • callback:创建回调,返回 (err, subWindow) 两个参数

注意事项:

  • 子窗口名称必须唯一
  • 子窗口默认不可见,需调用 showWindow() 显示
  • 子窗口需要通过 setUIContent 设置加载页面

3.4 getMainWindow()

异步获取主窗口(推荐使用 getMainWindowSync 替代)。

windowStage.getMainWindow((err, mainWindow) => {
  if (!err.code) {
    // 使用主窗口
  }
});

3.5 getLastWindow(callback)

获取当前应用内最上层的子窗口。

windowStage.getLastWindow((err, topWindow) => {
  if (!err.code) {
    hilog.info(0x0000, 'app', `最上层窗口ID: ${topWindow.getWindowProperties().id}`);
  }
});

3.6 setWindowLayoutFullScreen

通过 WindowStage 设置全屏布局(与通过 Window 设置效果一致)。

// 推荐在 loadContent 回调中通过主窗口设置
let mainWindow = windowStage.getMainWindowSync();
mainWindow.setWindowLayoutFullScreen(true);

四、完整示例:WindowStage 综合应用

以下示例展示如何在 onWindowStageCreate 中完成窗口初始化、全屏设置、避让区域获取、全局上下文存储等操作。

4.1 EntryAbility 完整实现

import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0000;

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, 'app', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'app', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.info(DOMAIN, 'app', 'onWindowStageCreate');

    // Step 1: 加载主页面
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'app', '加载失败: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'app', '页面加载成功');

      // Step 2: 获取UI上下文并存储到AppStorage
      let mainWindow = windowStage.getMainWindowSync();
      let uiContext = mainWindow.getUIContext();
      AppStorage.setOrCreate('uiContext', uiContext);

      // Step 3: 存储windowStage供页面使用
      AppStorage.setOrCreate('windowStage', windowStage);

      // Step 4: 存储主窗口ID
      AppStorage.setOrCreate('mainWindowId',
        mainWindow.getWindowProperties().id);

      // Step 5: 设置全屏布局
      mainWindow.setWindowLayoutFullScreen(true);

      // Step 6: 获取状态栏避让区域
      let sysAvoidArea = mainWindow.getWindowAvoidArea(
        window.AvoidAreaType.TYPE_SYSTEM);
      let topRectHeight = sysAvoidArea.topRect.height;
      AppStorage.setOrCreate('topRectHeight', topRectHeight);

      // Step 7: 获取导航条避让区域
      let navAvoidArea = mainWindow.getWindowAvoidArea(
        window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
      let bottomRectHeight = navAvoidArea.bottomRect.height;
      AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
    });
  }

  onWindowStageDestroy(): void {
    hilog.info(DOMAIN, 'app', 'onWindowStageDestroy');
  }

  onForeground(): void {
    hilog.info(DOMAIN, 'app', 'onForeground');
  }

  onBackground(): void {
    hilog.info(DOMAIN, 'app', 'onBackground');
  }
}

4.2 页面中使用 WindowStage 创建子窗口(状态管理V2版本)

import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';

@Entry
@ComponentV2
struct Index {
  @Local windowStage: window.WindowStage =
    AppStorage.get('windowStage') as window.WindowStage;
  @Local isSubWindowCreated: boolean = false;

  // 创建子窗口
  createSubWindow(): void {
    if (this.isSubWindowCreated) {
      hilog.info(0x0000, 'app', '子窗口已创建');
      return;
    }
    this.windowStage.createSubWindow('demoSubWin', (err, subWin) => {
      if (err.code) {
        hilog.error(0x0000, 'app', '创建失败: %{public}s', err.message);
        return;
      }
      // 设置子窗口页面
      subWin.setUIContent('subwindow/SubPage', () => {
        subWin.setWindowBackgroundColor('#00000000');
      });
      // 设置位置和大小
      let uiContext = this.windowStage.getMainWindowSync().getUIContext();
      subWin.moveWindowTo(0, 300);
      subWin.resize(uiContext.vp2px(60), uiContext.vp2px(60));
      // 显示子窗口
      subWin.showWindow();
      this.isSubWindowCreated = true;
    });
  }

  // 销毁子窗口
  async destroySubWindow(): Promise<void> {
    try {
      let subWin = window.findWindow('demoSubWin');
      await subWin.destroyWindow();
      this.isSubWindowCreated = false;
    } catch (err) {
      hilog.error(0x0000, 'app', '销毁失败: %{public}s', JSON.stringify(err));
    }
  }

  build() {
    Column({ space: 20 }) {
      Text('WindowStage 示例')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      Button(this.isSubWindowCreated ? '销毁子窗口' : '创建子窗口')
        .onClick(() => {
          if (this.isSubWindowCreated) {
            this.destroySubWindow();
          } else {
            this.createSubWindow();
          }
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

五、WindowStage 与多窗口协调

5.1 窗口焦点管理

在多窗口场景下,需要管理窗口焦点的切换:

// 将焦点从子窗口转移回主窗口
setTimeout(() => {
  let subId = window.findWindow('subWin').getWindowProperties().id;
  let mainId = windowStage.getMainWindowSync().getWindowProperties().id;
  window.shiftAppWindowFocus(subId, mainId);
}, 500);

5.2 EventHub 事件通信

通过 eventHub 实现 Ability 与页面之间的事件通信:

// EntryAbility 中发送事件
onForeground(): void {
  this.context.eventHub.emit('onForeground');
}

// 页面中监听事件
aboutToAppear(): void {
  let ctx = this.getUIContext().getHostContext();
  ctx?.eventHub.on('onForeground', () => {
    // 应用回到前台时的处理逻辑
  });
}

aboutToDisappear(): void {
  let ctx = this.getUIContext().getHostContext();
  ctx?.eventHub.off('onForeground');
}

5.3 通过 AppStorage 实现全局数据共享

WindowStage 相关的全局数据推荐通过 AppStorage 管理:

// 存储
AppStorage.setOrCreate('windowStage', windowStage);
AppStorage.setOrCreate('uiContext', uiContext);
AppStorage.setOrCreate('topRectHeight', topRectHeight);
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);

// 页面中读取
@StorageLink('windowStage') windowStage: window.WindowStage;
@StorageProp('topRectHeight') topRectHeight: number = 0;

六、开发要点与最佳实践

6.1 loadContent 回调中的初始化顺序

loadContent 回调
  ├── 1. 获取 UIContext 并存储
  ├── 2. 存储 WindowStage
  ├── 3. 设置全屏布局
  ├── 4. 获取避让区域高度
  └── 5. 其他初始化操作

顺序很重要:必须先 loadContent 成功,再获取主窗口进行后续设置。

6.2 子窗口页面路由配置

子窗口页面需要在 main_pages.json 中注册:

{
  "src": [
    "pages/Index",
    "subwindow/SubPage"
  ]
}

6.3 避免重复创建子窗口

// 创建前检查是否已存在
try {
  let existing = window.findWindow('subWinName');
  // 已存在,直接显示
  existing.showWindow();
} catch (err) {
  // 不存在,创建新窗口
  windowStage.createSubWindow('subWinName', callback);
}

6.4 应用退出时清理子窗口

onBackground(): void {
  // 应用进入后台时,可选择隐藏或销毁子窗口
  try {
    let subWin = window.findWindow('subWinName');
    subWin.hideWindow();
  } catch (err) {
    // 子窗口不存在
  }
}

七、WindowStage 接口方法速查表

方法 说明 异步/同步
loadContent(path, callback) 加载主页面内容 回调
getMainWindowSync() 同步获取主窗口 同步
getMainWindow(callback) 异步获取主窗口 回调
createSubWindow(name, callback) 创建应用子窗口 回调
getLastWindow(callback) 获取最上层子窗口 回调
setWindowLayoutFullScreen(fullScreen) 设置全屏布局 异步

八、总结

WindowStage 是 HarmonyOS 应用窗口管理的调度中心,开发者需要重点掌握:

  1. 生命周期管理:理解 onWindowStageCreateonWindowStageDestroy 的时机
  2. 页面加载loadContent 是所有窗口操作的起点
  3. 主窗口获取getMainWindowSync 获取主窗口后进行全屏、避让区域等设置
  4. 子窗口创建createSubWindow 实现应用内悬浮窗效果
  5. 全局数据管理:通过 AppStorage 在 Ability 和页面间共享窗口信息
  6. 事件通信:通过 eventHub 实现 Ability 与页面的松耦合通信
  7. 状态管理V2:使用 @ComponentV2 + @Local 替代 V1 装饰器,与 AppStorage.get() 配合使用

相关文档:

Logo

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

更多推荐