鸿蒙(HarmonyOS/ArkUI·Stage模型)多窗口与浮窗体系实战指南!
我是兰瓶Coding,一枚刚踏入鸿蒙领域的转型小白,原是移动开发中级,如下是我学习笔记,若对你所有帮助,还请不吝啬的给个大大的赞~
·
我是兰瓶Coding,一枚刚踏入鸿蒙领域的转型小白,原是移动开发中级,如下是我学习笔记《零基础学鸿蒙》,若对你所有帮助,还请不吝啬的给个大大的赞~
1 窗口体系概览
- 主窗(Main Window):每个
WindowStage挂载 1 个主窗,承载页面路由与绝大多数 UI。 - 子窗(Sub Window / Auxiliary Window):附着于主窗之上,用于弹出层、工具条、画中画、并行视图等。
- 全局悬浮窗(Global Floating Window):跨应用叠加显示,常用于系统级工具球、录屏控件等(强权限、严格 UX 规范)。
- 沉浸式(Immersive / Fullscreen):隐藏或半透明系统栏,扩大内容可视区域(需遵循安全与可达性限制)。
2 获取主窗:WindowStage → MainWindow
在 Ability 的 onWindowStageCreate(windowStage: WindowStage) 生命周期中获取并初始化主窗。
import window from '@ohos.window';
export default class MainAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
// 1) 获取主窗(异步/回调两种形态,以下为 Promise 形态示例)
windowStage.getMainWindow().then((mainWin: window.Window) => {
// 2) 配置主窗属性(尺寸、沉浸、系统栏等)
mainWin.setWindowFocusable(true);
// 例:设置窗口模式(全屏/分屏/浮窗,具体枚举以 SDK 为准)
// mainWin.setWindowMode(window.WindowMode.FULLSCREEN);
// 例:设置内容布局是否延伸至系统栏区域
// mainWin.setWindowLayoutFullScreen(true);
// 3) 监听窗口事件
mainWin.on('windowSizeChange', (size) => {
// 自适应布局
});
mainWin.on('avoidAreaChange', (area) => {
// 处理刘海/圆角/系统栏避让
});
});
}
}
要点
getMainWindow()可能为Promise或回调,注意 SDK 版本差异。- 监听
windowSizeChange/avoidAreaChange/keyboardHeightChange做自适应。 - 使用
WindowStage.setUIContent(或等效)挂载根路由页面。
3 创建子窗:Overlay / Tooling / Sidecar
子窗附着于主窗,适合工具条、悬浮面板、画中画等局部场景。子窗不应滥用跨应用叠加能力。
async function createSubWindow(parent: window.Window) {
// 1) 构造子窗参数(名称、类型、尺寸、对齐、层级)
const cfg: window.SubWindowOptions = {
name: 'tool_panel',
// type/flags 以 SDK 实际枚举为准,例如:TOOL_WINDOW / FLOATING_SUB_WINDOW
// type: window.WindowType.FLOATING_SUB_WINDOW,
width: 360,
height: 420,
// 例:相对父窗的定位
x: 24,
y: 80,
focusable: true,
touchable: true
};
// 2) 创建并显示
const subWin = await parent.createSubWindow(cfg);
await subWin.setUIContent('pages/ToolPanel'); // 载入 ETS 页面
await subWin.show();
// 3) 生命周期与通信
subWin.on('windowClose', () => {
// 清理资源
});
// 父子窗通信:状态提升/事件总线/分布式数据(仅同应用)
}
子窗最佳实践
- 尺寸与位置:遵循最小触控面积(≥48dp),不遮挡关键导航区域。
- 焦点管理:显式
focusable,ESC/返回键关闭;非阻塞主线程。 - 可访问性:为按钮/图标提供替代文本,支持键盘/旋钮切换。
- 性能:避免高频重绘(动画/阴影/模糊谨慎用)。
4 创建全局悬浮窗(需高权限)
全局悬浮窗可覆盖他应用,仅适合系统工具级场景(如录屏按钮、通话气泡)。需要声明与动态申请系统悬浮权限(名称随版本可能不同,常见为 ohos.permission.SYSTEM_FLOAT_WINDOW)。
// 1) 清单声明(config.json/Module.json5)
/*
"requestPermissions": [
{ "name": "ohos.permission.SYSTEM_FLOAT_WINDOW", "reason": "用于提供跨应用的全局工具球" }
]
*/
// 2) 运行时申请(示例)
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
async function ensureFloatPermission(context: Context): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
const perms: Permissions[] = ['ohos.permission.SYSTEM_FLOAT_WINDOW'];
// 查询 & 申请
const grantStatus = await atManager.requestPermissionsFromUser(context, perms);
return grantStatus?.[0] === 0; // 0 表示授予(以实际返回为准)
}
// 3) 创建全局悬浮窗
import window from '@ohos.window';
async function createGlobalFloat(context: Context) {
const ok = await ensureFloatPermission(context);
if (!ok) { return; }
const opt: window.WindowOptions = {
name: 'global_bubble',
// type: window.WindowType.SYSTEM_FLOAT, // 具体枚举以 SDK 为准
// flags: window.WindowFlag.TOUCHABLE | window.WindowFlag.FOCUSABLE,
width: 72,
height: 72
};
const floatWin = await window.createWindow(context, opt);
await floatWin.setUIContent('pages/GlobalBubble');
await floatWin.setWindowKeepScreenOn(false); // 严禁无必要常亮
await floatWin.show();
// 拖拽/吸附边缘/单击收起等交互逻辑在 ETS 页面中实现
}
全局悬浮窗 UX & 合规
- 使用场景极度克制:仅系统工具型、短时辅助。不做广告/误导点击/信息遮挡。
- 尺寸:小而不遮挡(如 56–72dp),提供可拖拽与快速关闭。
- 前台服务提示:在任务栏/通知中心明确展示正在运行的全局控件。
- 隐私:不得截取他应用隐私内容;不得诱导权限;严控采集与上报频率。
- 多显示器/横竖屏:保持位置与可达性一致。
5 沉浸式(Immersive)条件、限制与最佳实践
典型场景:视频、游戏、阅读/相册、导航/地图、AR/全景。
不建议:金融交易、账号安全、信息输入等需要系统栏/返回链路明确的场景。
function enableImmersive(win: window.Window) {
// 关键能力(示例名):
// 1) 内容铺满:不被系统栏裁切
// win.setWindowLayoutFullScreen(true);
// 2) 系统栏外观与可见性:隐藏或半透明(需考虑安全手势)
// win.setSystemBarProperties({
// statusBarColor: '#00000000', // 透明
// statusBarContentColor: 'light', // 图标文字亮色
// navigationBarVisibility: false
// });
// 3) 手势回退/系统唤出:保持边缘滑动召回能力
}
最佳实践
- 可逃生通道:边缘滑动可呼出系统栏;提供明确的“退出全屏”区域或手势。
- 安全区自适配:监听
avoidAreaChange,对齐刘海/圆角/打孔区。 - 交互密度:全屏下减少细小点击目标,优先手势/大按钮/语音。
- 亮度/功耗:长时沉浸内容动态调暗 UI 背景,降低常亮负载。
6 权限申请与 UX 规范清单
常见权限(按需最小化)
ohos.permission.SYSTEM_FLOAT_WINDOW:全局悬浮窗(强管控)。ohos.permission.MICROPHONE/CAMERA/LOCATION:若悬浮窗含录音/拍摄/定位控件(强提示、可撤回)。ohos.permission.KEEP_SCREEN_ON(如有):仅在导航/视频播放场景短时启用。
UX 规范
- 透明度与阴影:保证可读性但避免重绘过载;动画≤200ms。
- 手势冲突:避让系统边缘手势;拖拽采用“按下-跟随-吸附”三段式。
- 可达性:所有控件≥48dp;支持屏幕阅读器与硬件旋钮/方向键。
- 多窗口协同:主窗在前台时,子窗/浮窗不应强制抢焦点。
7 性能与电量评估
7.1 性能基线
- 窗口数量上限:控制并发子窗数量(建议≤3),浮窗仅 1 个活跃实例。
- 合成与重绘:减少半透明/阴影/模糊;动画使用硬件加速属性(位移/缩放/透明度),避免逐帧重排。
- 渲染帧率:静态 UI 锁 30fps;动画期间临时升至 60fps 后回落。
- 事件合并:高频拖拽/滚动做节流/合帧(如 16–32ms 合并)。
7.2 电量优化
- 可见性驱动:
onForeground/onBackground与windowVisibilityChange中暂停动画/定时器/传感器。 - 刷新策略:浮窗处于静止时停止重绘;仅状态变更时
requestRender(). - 定位与传感:非导航场景禁用持续定位;使用“显著位置变化”与低频策略。
- 网络:合并上报、压缩与去抖;夜间与后台使用更长同步间隔。
- 屏幕常亮:仅在必要场景短时启用,随场景退出立即恢复系统策略。
建议指标
- 主/子/浮窗 平均 CPU < 8% / 峰值 < 20%(中端机型参考)。
- 浮窗空闲 GPU 占用≈0%;拖拽期间平均帧时 ≤16.6ms。
- 后台 10 分钟功耗增量 < 1%(不含导航/视频)。
8 调试与可观测性
- 指标埋点:窗口创建/显示/隐藏耗时、帧时 P50/P95、掉帧率、合成层数、权限弹框点击率。
- 日志分级:窗口生命周期、权限申请结果、异常捕获(含用户拒绝/撤回)。
- A/B 验证:沉浸式开关、浮窗尺寸/位置、拖拽吸附算法。
- 故障注入:模拟权限撤回、分辨率变化、旋转/多显示器切换。
9 常见陷阱与规避
- 过度使用全局悬浮窗:被系统或应用市场拒绝;请退回子窗或通知样式。
- 遮挡系统手势与导航:造成“无法返回/退出”的糟糕体验;务必避让与提供退出通道。
- 频繁重建窗口:应复用窗口实例,使用显示/隐藏管理生命周期。
- 忽视可达性:缺少替代文本/焦点循环/硬件控制支持,影响无障碍审核。
- 亮度与常亮滥用:显著增加功耗,影响续航。
10 小结与落地清单
- ✅
WindowStage.getMainWindow()获取并初始化主窗,订阅尺寸/避让区变化。 - ✅ 子窗用于同应用的工具/面板,控制数量、尺寸与焦点。
- ✅ 全局悬浮窗仅限系统级短时辅助场景,严格权限与 UX 规范。
- ✅ 沉浸式仅用于内容消费/导航类,保留可逃生手势与安全区适配。
- ✅ 建立性能+功耗基线与可观测性,按可见性暂停无效渲染与传感。
…
(未完待续)
更多推荐


所有评论(0)