《悬浮窗效果》一、Interface_Window使用指南
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 像素单位转换(重要)
moveWindowTo 和 resize 的参数单位是 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 窗口管理的基石。掌握以下核心能力,即可应对绝大多数窗口相关开发场景:
- 获取窗口实例:通过
WindowStage获取主窗口,通过createSubWindow创建子窗口 - 位置与大小控制:
moveWindowTo+resize实现窗口定位与缩放(注意 px 单位转换) - 属性设置:背景透明、全屏布局、系统栏样式
- 焦点管理:
shiftAppWindowFocus在多窗口间切换焦点 - 避让区域:
getWindowAvoidArea实现沉浸式布局 - 状态管理V2适配:使用
@ComponentV2+@Local替代@Component+@State,获得更细粒度的响应式更新
更多推荐




所有评论(0)