窗口管理基础:WindowStage获取与窗口属性设置(66)
在鸿蒙(HarmonyOS)的 Stage 模型中,窗口管理是应用 UI 呈现的核心。WindowStage 是应用主窗口的容器,负责管理窗口的生命周期和 UI 页面的加载。以下是关于 WindowStage 获取与窗口属性设置的基础实战:
一、 WindowStage 的获取方式
在应用开发中,获取 WindowStage 实例主要有两种场景和方式:
1. 在 UIAbility 生命周期中获取(推荐)
在 UIAbility 的 onWindowStageCreate 回调中,系统会直接传入 windowStage 实例。这是最标准、最安全的获取方式,通常用于加载首页和监听窗口生命周期事件。
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
// 1. 加载主页面
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
console.error('加载页面失败:', err);
return;
}
});
// 2. 订阅窗口生命周期事件(如前后台切换、获焦/失焦)
windowStage.on('windowStageEvent', (data: window.WindowStageEventType) => {
switch (data) {
case window.WindowStageEventType.SHOWN:
console.info('窗口进入前台');
break;
case window.WindowStageEventType.HIDDEN:
console.info('窗口进入后台');
break;
}
});
}
}
2. 在 Page 页面中获取(跨组件传递)
如果需要在具体的 ArkUI 页面(如 Index.ets)中获取 WindowStage(例如为了创建子窗口),可以通过 AppStorage 进行跨组件传递,或者通过 UIAbilityContext 获取。
// 在 Ability 中存入 AppStorage
onWindowStageCreate(windowStage: window.WindowStage): void {
AppStorage.setOrCreate('windowStage', windowStage);
windowStage.loadContent('pages/Index');
}
// 在 Page 中获取
@Entry
@Component
struct Index {
aboutToAppear() {
let windowStage = AppStorage.get<window.WindowStage>('windowStage');
// 或者通过 Context 获取:
// let context = getContext(this) as common.UIAbilityContext;
// let ws = context.windowStage;
}
}
二、 获取主窗口并设置属性
WindowStage 是窗口管理器,要修改窗口的具体属性(如全屏、沉浸式、透明度等),需要先通过它获取主窗口(Main Window)对象。
onWindowStageCreate(windowStage: window.WindowStage): void {
// 获取主窗口实例
windowStage.getMainWindow((err, mainWindow) => {
if (err.code) {
console.error('获取主窗口失败:', err);
return;
}
// 设置窗口属性,例如:全屏显示
mainWindow.setWindowLayoutFullScreen(true, (err) => {
if (err.code) {
console.error('设置全屏失败:', err);
}
});
});
}
三、 自由窗口尺寸限制配置
对于支持自由窗口模式的设备(如平板、PC),开发者可以通过配置文件限制窗口的大小范围,防止布局因过度拉伸而错乱。
在 module.json5 的 abilities 标签中进行配置:
{
"module": {
"abilities": [
{
"name": "EntryAbility",
"minWindowWidth": 320, // 最小宽度 (vp)
"minWindowHeight": 240, // 最小高度 (vp)
"maxWindowWidth": 1440, // 最大宽度 (vp)
"maxWindowHeight": 900, // 最大高度 (vp)
"minWindowRatio": 0.5, // 最小宽高比
"maxWindowRatio": 2 // 最大宽高比
}
]
}
}
四、 子窗口(SubWindow)的创建与管理
除了主窗口,应用还可以通过 WindowStage 创建子窗口,常用于实现弹窗、悬浮窗或辅助面板。子窗口的生命周期依附于主窗口。
// 在 WindowStage 中创建子窗口
windowStage.createSubWindow('mySubWindow', (err, subWindow) => {
if (err.code) {
console.error('创建子窗口失败:', err);
return;
}
// 设置子窗口位置和大小
subWindow.moveWindowTo(300, 300);
subWindow.resize(500, 500);
// 为子窗口加载页面
subWindow.setUIContent('pages/SubPage', (err) => {
if (!err.code) {
// 显示子窗口
subWindow.showWindow();
}
});
});
开发建议
- 生命周期匹配:务必在
onWindowStageCreate中初始化窗口,并在onWindowStageDestroy中释放窗口资源和取消事件监听,避免内存泄漏。 - 沉浸式适配:开启全屏或沉浸式后,需注意避开系统状态栏和导航栏的遮挡区域(安全区),可使用
window.getLastWindow获取避开区域(AvoidArea)的坐标进行布局适配。 - 响应式布局:窗口大小改变时,应结合 ArkUI 的栅格布局(
GridRow/GridCol)和断点系统(Breakpoint),实现窗口缩放时的 UI 自适应。
五、 沉浸式体验优化:状态栏与导航栏定制
当应用开启全屏布局(setWindowLayoutFullScreen(true))后,内容会延伸至状态栏和导航栏区域。为了保证视觉协调与可读性,需要动态调整系统栏的样式。
import { window } from '@kit.ArkUI';
// 在获取到主窗口 windowClass 后
let sysBarProps: window.SystemBarProperties = {
statusBarColor: '#00000000', // 状态栏背景透明
navigationBarColor: '#00000000', // 导航栏背景透明
statusBarContentColor: '#ffffff', // 状态栏图标/文字颜色(白色)
navigationBarContentColor: '#ffffff' // 导航栏图标/文字颜色
};
windowClass.setWindowSystemBarProperties(sysBarProps).then(() => {
console.info('系统栏样式设置成功');
}).catch((err: BusinessError) => {
console.error('设置系统栏样式失败:', err);
});
六、 窗口安全与隐私保护
对于包含敏感信息(如密码输入、金融交易、私人聊天)的页面,必须防止被恶意截屏或录屏。
// 开启窗口隐私模式,系统级防截屏/录屏
let isPrivacyMode: boolean = true;
windowClass.setWindowPrivacyMode(isPrivacyMode, (err: BusinessError) => {
if (err.code) {
console.error('开启隐私模式失败:', err);
return;
}
console.info('隐私模式已开启,当前窗口内容受保护');
});
七、 窗口属性精细化控制
除了全屏和尺寸,鸿蒙还支持对窗口的交互行为进行细粒度控制,例如禁止触摸穿透、设置窗口透明度、保持屏幕常亮等。
// 1. 设置窗口是否可触摸(常用于弹窗时屏蔽底层交互)
windowClass.setWindowTouchable(true);
// 2. 获取窗口详细属性(如当前宽高、是否聚焦等)
let properties = windowClass.getWindowProperties();
console.info(`当前窗口宽度: ${properties.windowRect.width}`);
console.info(`窗口是否可聚焦: ${properties.focusable}`);
// 3. 设置窗口背景透明度(实现毛玻璃或半透明悬浮效果)
// 注:透明度可通过 WindowProperties 或 ArkUI 的 .opacity() 结合实现
八、 进阶:多窗口协同与智能吸附(PC/大屏场景)
在鸿蒙 PC 或折叠屏设备上,多窗口协同是核心体验。通过监听窗口位置变化,可以实现类似桌面操作系统的“磁吸”效果。
import window from '@ohos.window';
// 定义吸附阈值(单位:px)
const ADSORB_THRESHOLD = 10;
// 监听子窗口位置变化
subWindow.on('windowPositionChange', async (currentPos) => {
try {
// 获取当前应用内所有窗口
const windowStage = await window.getLastWindowStage();
const allWindows = await windowStage.getWindows();
let finalX = currentPos.x;
let finalY = currentPos.y;
// 遍历其他窗口,计算边缘距离
for (let win of allWindows) {
if (win.getName() === subWindow.getName()) continue;
const refPos = await win.getPosition();
const refSize = await win.getWindowSize();
// 示例:右边缘吸附左边缘
if (Math.abs(finalX + currentSize.width - refPos.x) < ADSORB_THRESHOLD) {
finalX = refPos.x - currentSize.width;
}
}
// 如果触发了吸附,强制更新位置
if (finalX !== currentPos.x || finalY !== currentPos.y) {
subWindow.setPosition(finalX, finalY);
}
} catch (err) {
console.error('窗口吸附计算失败:', err);
}
});
建议
- 子窗口 vs 浮层(Float Layer):官方建议,如果仅仅是应用内的弹窗、下拉菜单或提示框,优先使用 ArkUI 的控件浮层能力,而不是创建独立的子窗口。子窗口的创建开销较大,且在分屏/自由窗口模式下,控件浮层的跟随与响应性能更优。
- 异步操作规范:所有的窗口管理 API(如
getMainWindow,setPosition,setWindowPrivacyMode)均为异步操作(返回 Promise)。在复杂逻辑中务必使用async/await或.then()妥善处理,避免因窗口对象未初始化完成而导致的空指针异常。 - 资源释放:对于动态创建的子窗口,在页面销毁(
aboutToDisappear)或不再需要时,必须调用destroyWindow()进行销毁,防止内存泄漏和僵尸窗口。
更多推荐



所有评论(0)