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

摘要: 在 HarmonyOS 应用开发中,Window 接口是窗口管理的核心。本文基于 HarmonyOS NEXT官方文档与实战经验,系统讲解 Window 接口的核心方法、使用场景和完整示例代码,帮助开发者快速掌握窗口创建、移动、缩放、属性设置等关键能力。


效果

一、Window 接口概述

Window 接口位于 @kit.ArkUI 模块的 window 命名空间下,代表应用中的一个窗口实例。它可以是主窗口(Main Window)子窗口(Sub Window)系统窗口(System Window)

1.1 导入方式

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

1.2 获取 Window 实例的常见方式

方式 说明 适用场景
windowStage.getMainWindowSync() 同步获取应用主窗口 onWindowStageCreate 中获取主窗口
window.findWindow(name) 通过窗口名称查找窗口 查找已创建的子窗口
window.createWindow(config) 异步创建新窗口 创建悬浮窗类型的系统窗口
windowStage.createSubWindow(name) 在 WindowStage 上创建子窗口 创建应用内子窗口(如悬浮窗)

注意: findWindow 需要在窗口已创建后才能调用,否则会抛出异常。


二、核心方法详解

2.1 窗口位置控制

moveWindowTo(x, y)

将窗口移动到屏幕指定坐标位置。

// 同步方式
windowInstance.moveWindowTo(x: number, y: number): Promise<void>;

// 回调方式
windowInstance.moveWindowTo(x: number, y: number, callback: AsyncCallback<void>): void;

参数说明:

  • x:窗口左上角横坐标(单位:px)
  • y:窗口左上角纵坐标(单位:px)

使用示例:

// 将窗口移动到屏幕左上角
await windowInstance.moveWindowTo(0, 0);

// 将窗口移动到指定位置
windowInstance.moveWindowTo(100, 200, (err) => {
  if (err.code) {
    console.error(`移动失败: ${JSON.stringify(err)}`);
  }
});
moveWindow(params)

通过传入 WindowPosition 对象移动窗口。

let position: window.WindowPosition = { x: 100, y: 200 };
await windowInstance.moveWindow(position);

2.2 窗口大小控制

resize(width, height)

调整窗口大小。

// 同步方式
windowInstance.resize(width: number, height: number): Promise<void>;

// 回调方式
windowInstance.resize(width: number, height: number, callback: AsyncCallback<void>): void;

参数说明:

  • width:窗口宽度(单位:px)
  • height:窗口高度(单位:px)
resizeAsync(width, height)

异步调整窗口大小,返回 Promise。

try {
  await windowInstance.resizeAsync(300, 500);
  console.info('窗口大小调整成功');
} catch (err) {
  console.error(`调整失败: ${JSON.stringify(err)}`);
}

注意: 传入的宽高值为像素(px),若设计稿使用 vp 单位,需通过 uiContext.vp2px() 进行转换。

2.3 窗口显示与隐藏

// 显示窗口
await windowInstance.showWindow();

// 隐藏窗口
await windowInstance.hideWindow();

2.4 窗口属性设置

setWindowBackgroundColor(color)

设置窗口背景颜色,支持透明背景。

// 设置透明背景(悬浮窗常用)
windowInstance.setWindowBackgroundColor('#00000000');

// 设置白色背景
windowInstance.setWindowBackgroundColor('#FFFFFF');
setWindowLayoutFullScreen(isFullScreen)

设置窗口是否全屏布局。

let isLayoutFullScreen = true;
await windowInstance.setWindowLayoutFullScreen(isLayoutFullScreen);
setWindowSystemBarProperties(properties)

设置系统栏(状态栏、导航条)属性。

await windowInstance.setWindowSystemBarProperties({
  statusBarContentColor: '#FFFFFF',     // 状态栏文字颜色
  navigationBarContentColor: '#000000', // 导航条文字颜色
  statusBarColor: '#FF0000'            // 状态栏背景色(已废弃,建议使用沉浸式)
});
getWindowProperties()

获取窗口属性信息。

let properties = windowInstance.getWindowProperties();
console.info(`窗口ID: ${properties.id}`);
console.info(`窗口类型: ${properties.type}`);
console.info(`窗口区域: ${JSON.stringify(properties.windowRect)}`);

2.5 窗口避让区域

getWindowAvoidArea(type)

获取窗口避让区域(如状态栏、导航条区域),用于沉浸式布局。

// 获取导航条避让区域
let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR;
let avoidArea = windowInstance.getWindowAvoidArea(type);
let bottomRectHeight = avoidArea.bottomRect.height;

// 获取状态栏避让区域
type = window.AvoidAreaType.TYPE_SYSTEM;
avoidArea = windowInstance.getWindowAvoidArea(type);
let topRectHeight = avoidArea.topRect.height;

2.6 窗口焦点切换

window.shiftAppWindowFocus(from, to)

在两个窗口之间切换焦点,常用于子窗口操作后将焦点归还主窗口。

let subWindowId = window.findWindow('mySubWindow').getWindowProperties().id;
let mainWindowId = windowStage.getMainWindowSync().getWindowProperties().id;
// 将焦点从子窗口转移到主窗口
window.shiftAppWindowFocus(subWindowId, mainWindowId);

三、完整示例:创建并控制一个子窗口

以下示例展示如何在主页面中创建一个子窗口,并实现移动、缩放、显示/隐藏操作。

3.1 EntryAbility 中保存 WindowStage

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

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', '加载失败: %{public}s', JSON.stringify(err));
        return;
      }
      // 将 windowStage 存入 AppStorage,供页面使用
      AppStorage.setOrCreate('windowStage', windowStage);

      // 获取主窗口并设置全屏
      let mainWindow = windowStage.getMainWindowSync();
      mainWindow.setWindowLayoutFullScreen(true);

      // 获取避让区域高度
      let avoidArea = mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
      AppStorage.setOrCreate('topRectHeight', avoidArea.topRect.height);

      let navArea = mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
      AppStorage.setOrCreate('bottomRectHeight', navArea.bottomRect.height);
    });
  }
}

3.2 页面中创建并操作子窗口(状态管理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 subWindow: window.Window | undefined = undefined;
  @Local isSubWindowCreated: boolean = false;

  // 创建子窗口
  createSubWindow(): void {
    if (this.isSubWindowCreated) { return; }
    this.windowStage.createSubWindow('demoSubWindow', (err, win) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', '创建子窗口失败: %{public}s', err.message);
        return;
      }
      this.subWindow = win;
      // 设置子窗口加载页面
      win.setUIContent('subwindow/SubWindowPage', () => {
        win.setWindowBackgroundColor('#00000000');
      });
      // 设置位置和大小(注意单位是px,需vp2px转换)
      let uiCtx = this.windowStage.getMainWindowSync().getUIContext();
      win.moveWindowTo(0, 300);
      win.resize(uiCtx.vp2px(60), uiCtx.vp2px(60));
      // 显示子窗口
      win.showWindow();
      this.isSubWindowCreated = true;
    });
  }

  // 移动子窗口
  async moveSubWindow() {
    if (this.subWindow) {
      await this.subWindow.moveWindowTo(100, 400);
    }
  }

  // 调整子窗口大小
  async resizeSubWindow() {
    if (this.subWindow) {
      await this.subWindow.resizeAsync(300, 300);
    }
  }

  // 隐藏子窗口
  async hideSubWindow() {
    if (this.subWindow) {
      await this.subWindow.hideWindow();
    }
  }

  // 销毁子窗口
  async destroySubWindow(): Promise<void> {
    if (this.subWindow) {
      await this.subWindow.destroyWindow();
      this.subWindow = undefined;
      this.isSubWindowCreated = false;
    }
  }

  build() {
    Column({ space: 16 }) {
      Button(this.isSubWindowCreated ? '销毁子窗口' : '创建子窗口')
        .onClick(() => {
          if (this.isSubWindowCreated) {
            this.destroySubWindow();
          } else {
            this.createSubWindow();
          }
        })
      Button('移动窗口').onClick(() => { this.moveSubWindow(); })
      Button('调整大小').onClick(() => { this.resizeSubWindow(); })
      Button('隐藏窗口').onClick(() => { this.hideSubWindow(); })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

四、开发要点与常见问题

4.1 像素单位转换(重要)

moveWindowToresize 的参数单位是 px(物理像素),而 ArkUI 布局使用 vp(虚拟像素)。在设置窗口大小时必须进行转换,否则窗口位置和尺寸会与预期不符:

let uiContext = windowStage.getMainWindowSync().getUIContext();
let widthInPx = uiContext.vp2px(50);  // 50vp 转 px
let heightInPx = uiContext.vp2px(50);
await windowInstance.resize(widthInPx, heightInPx);

4.2 子窗口与主窗口焦点管理

子窗口获得焦点后,主窗口将无法接收用户输入。操作完子窗口后,通常需要归还焦点:

// 延时归还焦点(等待动画完成)
setTimeout(() => {
  let subId = window.findWindow('subWin').getWindowProperties().id;
  let mainId = windowStage.getMainWindowSync().getWindowProperties().id;
  window.shiftAppWindowFocus(subId, mainId);
}, 500);

4.3 透明背景设置

创建悬浮窗效果时,必须设置窗口背景为透明:

windowInstance.setWindowBackgroundColor('#00000000');

同时,子窗口加载页面的根容器也应设置透明背景:

Column() {
  // 悬浮窗UI内容
}
.backgroundColor(Color.Transparent)

4.4 获取屏幕信息

使用 display 模块获取屏幕尺寸,用于边界计算:

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

let screenInfo = display.getDefaultDisplaySync();
let screenWidth = screenInfo.width;   // 屏幕宽度(px)
let screenHeight = screenInfo.height; // 屏幕高度(px)

五、Window 接口方法速查表

方法 说明 异步/同步
moveWindowTo(x, y) 移动窗口到指定坐标 异步
moveWindow(position) 移动窗口 异步
resize(w, h) 调整窗口大小 异步
resizeAsync(w, h) 异步调整窗口大小 Promise
showWindow() 显示窗口 异步
hideWindow() 隐藏窗口 异步
destroyWindow() 销毁窗口 异步
setWindowBackgroundColor(color) 设置背景颜色 异步
setWindowLayoutFullScreen(fullScreen) 设置全屏布局 异步
setWindowSystemBarProperties(props) 设置系统栏属性 异步
getWindowProperties() 获取窗口属性 同步
getWindowAvoidArea(type) 获取避让区域 同步
setUIContent(path, callback) 设置子窗口页面 回调
getUIContext() 获取UI上下文 同步
window.findWindow(name) 按名称查找窗口 同步
window.createWindow(config) 创建窗口 异步
window.shiftAppWindowFocus(from, to) 切换窗口焦点 异步

六、总结

Window 接口是 HarmonyOS 窗口管理的基石。掌握以下核心能力,即可应对绝大多数窗口相关开发场景:

  1. 获取窗口实例:通过 WindowStage 获取主窗口,通过 createSubWindow 创建子窗口
  2. 位置与大小控制moveWindowTo + resize 实现窗口定位与缩放(注意 px 单位转换)
  3. 属性设置:背景透明、全屏布局、系统栏样式
  4. 焦点管理shiftAppWindowFocus 在多窗口间切换焦点
  5. 避让区域getWindowAvoidArea 实现沉浸式布局
  6. 状态管理V2适配:使用 @ComponentV2 + @Local 替代 @Component + @State,获得更细粒度的响应式更新
Logo

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

更多推荐