《悬浮工具球》一、窗口开发概述使用指南
HarmonyOS窗口开发概述使用指南从零到一掌握应用窗口管理全流程适用版本HarmonyOS NEXTAPI 23/ DevEco Studio 6.1关键词窗口开发、WindowStage、子窗口、全屏布局、安全区避让、沉浸式体验效果一、前言为什么需要理解窗口开发在HarmonyOS应用开发中窗口Window是用户与应用交互的第一入口。无论是应用的主界面展示、弹窗提示、悬浮工具球还是沉浸式全屏体验都离不开窗口模块的支撑。很多开发者在接触HarmonyOS窗口开发时会遇到以下困惑主窗口和窗口有什么区别什么时候用子窗口全屏布局和沉浸式开发到底怎么配置安全区域状态栏、导航条怎么避让窗口生命周期如何与应用生命周期关联本文基于HarmonyOS官方文档结合实战开发经验系统梳理窗口开发的核心概念、关键API和典型使用场景并通过一个完整示例带你快速上手。二、核心概念窗口体系全景图2.1 窗口的分类HarmonyOS中的窗口分为两大类窗口类型说明典型场景系统窗口由系统创建和管理状态栏、导航条、输入法面板、音量调节应用窗口由应用创建用于显示应用界面主页面、弹窗、悬浮球、画中画应用窗口进一步分为子类型特点生命周期应用主窗口显示应用主界面在任务管理界面可见跟随UIAbility应用子窗口弹窗、悬浮球等辅助窗口不在任务管理界面显示跟随应用主窗口关键理解子窗口的生命周期跟随主窗口主窗口销毁时子窗口也会自动销毁。2.2 窗口模式HarmonyOS支持三种应用窗口模式模式说明适用设备全屏模式主窗口铺满整个屏幕手机、平板默认分屏模式多个应用并排显示平板、折叠屏自由窗口模式窗口可自由调整大小和位置类似PC窗口PC、2in1设备2.3 核心对象关系在Stage模型下窗口开发涉及三个核心对象它们的关系层层递进UIAbility应用入口 └── WindowStage窗口管理器 ├── 主窗口 Window应用主界面 └── 子窗口 Window弹窗、悬浮球等UIAbility应用入口一个UIAbility实例对应一个WindowStageWindowStage窗口管理器负责创建和管理窗口Window具体窗口实例提供窗口属性设置、位置移动、尺寸调整等能力三、窗口生命周期理解窗口生命周期是正确开发窗口基础。在Stage模型下窗口的生命周期与UIAbility紧密关联UIAbility.onCreate() ↓ UIAbility.onWindowStageCreate(windowStage) ← 窗口创建加载主页面 ↓ [应用运行中窗口可见] ↓ UIAbility.onWindowStageDestroy() ← 窗口即将销毁释放资源 ↓ UIAbility.onDestroy() ← Ability销毁关键生命周期回调回调方法触发时机典型操作onWindowStageCreateWindowStage创建完成加载主页面、创建子窗口、设置全屏onWindowStageDestroyWindowStage即将销毁释放子窗口、清理窗口资源onForeground应用切到前台恢复窗口状态onBackground应用切到后台保存窗口状态监听窗口生命周期事件还可以通过on(windowStageEvent)监听WindowStage的生命周期变化windowStage.on(windowStageEvent,(eventType:window.WindowStageEventType){// eventType 包括// SHOWN - 窗口显示// HIDDEN - 窗口隐藏// ACTIVE - 窗口获得焦点// INACTIVE - 窗口失去焦点switch(eventType){casewindow.WindowStageEventType.SHOWN:console.info(窗口已显示);break;casewindow.WindowStageEventType.ACTIVE:console.info(窗口获得焦点);break;}});四、关键开发场景与API使用4.1 加载主页面在onWindowStageCreate中通过loadContent为主窗口加载页面onWindowStageCreate(windowStage:window.WindowStage):void{windowStage.loadContent(pages/Index,(err){if(err.code){console.error(加载页面失败:,JSON.stringify(err));return;}console.info(页面加载成功);});}注意loadContent是异步方法但AppStorage.setOrCreate(windowStage, windowStage)等全局数据的设置必须在loadContent之前完成否则组件初始化时无法读取到全局数据。获取主窗口、设置全屏等操作可在loadContent回调中执行。4.2 获取主窗口并设置全屏windowStage.loadContent(pages/Index,(err){if(err.code)return;// 获取主窗口实例constmainWindow:window.WindowwindowStage.getMainWindowSync();// 设置全屏布局mainWindow.setWindowLayoutFullScreen(true).then((){console.info(全屏布局设置成功);}).catch((err:BusinessError){console.error(全屏布局设置失败:,JSON.stringify(err));});});4.3 安全区域避让全屏布局下内容会被状态栏和导航条遮挡。需要获取避让区域并动态调整布局// 获取状态栏高度顶部安全区constsysAreamainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);consttopInsetsysArea.topRect.height;// 单位px// 获取导航条高度底部安全区constnavAreamainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);constbottomInsetnavArea.bottomRect.height;// 单位px// 保存到全局供页面使用AppStorage.setOrCreate(topInset,topInset);AppStorage.setOrCreate(bottomInset,bottomInset);动态监听安全区变化如折叠屏展开、横竖屏切换mainWindow.on(avoidAreaChange,(data){if(data.typewindow.AvoidAreaType.TYPE_SYSTEM){AppStorage.setOrCreate(topInset,data.area.topRect.height);}elseif(data.typewindow.AvoidAreaType.TYPE_NAVIGATION_INDICATOR){AppStorage.setOrCreate(bottomInset,data.area.bottomRect.height);}});4.4 创建子窗口子窗口是悬浮球、弹窗等场景的核心载体// 通过WindowStage创建子窗口windowStage.createSubWindow(mySubWindow,(err,subWin){if(err.code0){console.error(创建子窗口失败:,err.message);return;}// 设置子窗口页面subWin.setUIContent(subwindow/SubPage);// 设置位置单位pxsubWin.moveWindowTo(500,1000);// 设置大小单位px需vp2px转换subWin.resize(200,200);// 设置背景透明subWin.setWindowBackgroundColor(#00000000);// 显示子窗口subWin.showWindow();});4.5 窗口焦点切换当子窗口需要操作后把焦点还给主窗口// 获取子窗口IDconstsubWinIdwindow.findWindow(mySubWindow).getWindowProperties().id;// 获取主窗口IDconstmainWinIdwindowStage.getMainWindowSync().getWindowProperties().id;// 焦点从子窗口转移到主窗口window.shiftAppWindowFocus(subWinId,mainWinId);五、完整示例从零搭建带子窗口的全屏应用下面通过一个完整的示例演示窗口开发的核心流程。5.1 工程结构entry/src/main/ets/ ├── entryability/ │ └── EntryAbility.ets // 应用入口配置窗口 ├── pages/ │ └── Index.ets // 主页面 └── subwindow/ └── SubPage.ets // 子窗口页面5.2 EntryAbility — 窗口配置入口import{UIAbility}fromkit.AbilityKit;import{window}fromkit.ArkUI;import{BusinessError}fromkit.BasicServicesKit;exportdefaultclassEntryAbilityextendsUIAbility{onWindowStageCreate(windowStage:window.WindowStage):void{// 1. 在loadContent之前设置AppStorage确保组件初始化时可读取AppStorage.setOrCreate(windowStage,windowStage);// 2. 获取主窗口配置全屏constwinwindowStage.getMainWindowSync();win.setWindowLayoutFullScreen(true);// 3. 获取安全区域consttopAreawin.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);AppStorage.setOrCreate(topInset,topArea.topRect.height);constbottomAreawin.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);AppStorage.setOrCreate(bottomInset,bottomArea.bottomRect.height);// 4. 监听安全区变化win.on(avoidAreaChange,(data){if(data.typewindow.AvoidAreaType.TYPE_SYSTEM){AppStorage.setOrCreate(topInset,data.area.topRect.height);}elseif(data.typewindow.AvoidAreaType.TYPE_NAVIGATION_INDICATOR){AppStorage.setOrCreate(bottomInset,data.area.bottomRect.height);}});// 5. 加载主页面此时AppStorage已就绪windowStage.loadContent(pages/Index,(err){if(err.code){console.error(加载失败:,JSON.stringify(err));return;}console.info(页面加载成功);});}}5.3 Index — 主页面加载子窗口import{window}fromkit.ArkUI;EntryComponentV2struct Index{privatewindowStage:window.WindowStageAppStorage.get(windowStage)aswindow.WindowStage;aboutToAppear():void{this.createSubWindow();}createSubWindow():void{this.windowStage.createSubWindow(demoSubWin,(err,win){if(err.code0)return;win.setUIContent(subwindow/SubPage);win.setWindowBackgroundColor(#00000000);win.moveWindowTo(800,1500);win.resize(this.getUIContext().vp2px(60),this.getUIContext().vp2px(60));win.showWindow();});}build(){Column(){Text(主页面内容).fontSize(24).fontWeight(FontWeight.Bold)}.width(100%).height(100%).justifyContent(FlexAlign.Center)}}5.4 SubPage — 子窗口页面EntryComponentV2struct SubPage{build(){Column(){Text(Hi).fontSize(20).fontColor(#FFFFFF)}.width(100%).height(100%).backgroundColor(#4A90D9).borderRadius(30).justifyContent(FlexAlign.Center)}}5.5 路由配置在main_pages.json中注册子窗口页面{src:[pages/Index,subwindow/SubPage]}六、开发注意事项与最佳实践6.1 AppStorage全局数据时序这是最容易踩坑的点。AppStorage.setOrCreate必须在loadContent之前调用否则组件初始化时Local变量读取AppStorage.get()将返回undefined// ❌ 错误写法在loadContent回调中设置AppStoragewindowStage.loadContent(pages/Index,(err){if(err.code)return;AppStorage.setOrCreate(windowStage,windowStage);// 组件已初始化读取为undefined});// ✅ 正确写法在loadContent之前设置AppStorageAppStorage.setOrCreate(windowStage,windowStage);windowStage.loadContent(pages/Index,(err){if(err.code)return;});6.2 异步操作时序loadContent和getMainWindowSync都是异步相关操作确保在loadContent回调中再执行依赖页面加载完成的窗口操作// ❌ 错误写法loadContent和getMainWindowSync并行调用windowStage.loadContent(pages/Index);constwinwindowStage.getMainWindowSync();// 可能获取到未加载完成的窗口// ✅ 正确写法在loadContent回调中操作windowStage.loadContent(pages/Index,(err){if(err.code)return;constwinwindowStage.getMainWindowSync();win.setWindowLayoutFullScreen(true);});6.3 单位转换窗口APImoveWindowTo、resize等的参数单位为物理像素px而ArkUI组件的属性单位为虚拟像素vp。必须使用vp2px进行转换constsizeVp60;// vpconstsizePxthis.getUIContext().vp2px(sizeVp);// 转换为pxwin.resize(sizePx,sizePx);6.4 子窗口页面注册子窗口加载的页面路径必须在main_pages.json中注册否则setUIContent会报错{src:[pages/Index,subwindow/SubPage]}6.5 窗口背景透明子窗口默认有白色背景如果需要透明效果如悬浮球必须设置背景色为透明win.setWindowBackgroundColor(#00000000);6.6 资源释放在onWindowStageDestroy中释放子窗口资源避免内存泄漏onWindowStageDestroy():void{// 销毁子窗口constsubWinwindow.findWindow(mySubWindow);if(subWin){subWin.destroyWindow();}}七、常见问题FAQQ1子窗口创建失败报错code 1300005这通常是因为窗口名称重复。每个子窗口的名称必须唯一不能创建两个同名子窗口。Q2全屏设置后内容被状态栏遮挡全屏布局下需要手动获取安全区域并设置padding。参考本文4.3 安全区域避让章节。Q3子窗口拖拽不跟手确保使用物理像素px单位进行窗口移动操作并在手势回调中直接更新窗口位置避免异步查询窗口属性导致延迟。Q4如何在子窗口中访问主窗口的数据通过AppStorage进行全局数据共享。在主页面的aboutToAppear中将需要共享的数据存入AppStorage在子窗口中通过AppStorage.get()获取。八、总结HarmonyOS窗口开发的核心知识点知识点要点核心对象UIAbility → WindowStage → Window层层递进主窗口配置loadContent加载页面 → getMainWindowSync获取窗口 → setWindowLayoutFullScreen全屏安全区避让getWindowAvoidArea获取避让区域 on(‘avoidAreaChange’)动态监听子窗口创建createSubWindow → setUIContent → moveWindowTo → resize → showWindow单位转换窗口API使用px组件使用vp用vp2px/px2vp转换时序保障窗口操作放在loadContent回调中避免并行调用掌握以上核心内容你就具备了HarmonyOS窗口开发的基础能力。在此基础上可以进一步探索悬浮工具球、画中画、自由窗口等高级场景。参考文档窗口开发概述管理应用窗口Stage模型ohos.window API参考

相关新闻

技术项目倦怠的成因分析与应对策略:从心理机制到工程实践

技术项目倦怠的成因分析与应对策略:从心理机制到工程实践

最近在技术社区看到不少开发者分享项目开发中的"倦怠期"体验——当一个功能模块或项目版本接近尾声时,反而失去了继续完成的动力。这种"第五季第三集完结了,但是我不想做了"的状态,在长期技术工作中其实相当常见。本文将…

2026/7/17 4:52:17 阅读更多 →
WSL2中解决systemd启动问题与daemonize安装指南

WSL2中解决systemd启动问题与daemonize安装指南

1. 问题背景与现象分析最近在WSL2环境中启动systemd服务时,遇到了"Cannot execute daemonize to start systemd"的错误提示。这个错误看似简单,但背后涉及到WSL2的特殊架构和Linux系统服务管理机制。作为长期使用WSL进行开发的工程师&#xff…

2026/7/17 4:52:17 阅读更多 →
将 GitHub Copilot 封装为本地 REST API 网关

将 GitHub Copilot 封装为本地 REST API 网关

1. 项目概述:这不是一个“调用 Copilot”的扩展,而是一个“把 Copilot 能力变成你自己的 API 网关”的工程你有没有过这种时刻:在 VS Code 里写代码,Copilot 的建议精准得像开了天眼;可一转身想把它集成进自己的 CI 流…

2026/7/17 4:50:16 阅读更多 →

最新新闻

PCL KdTree原理与实战:点云最近邻搜索核心技术与性能优化

PCL KdTree原理与实战:点云最近邻搜索核心技术与性能优化

1. 项目概述 如果你正在用PCL(Point Cloud Library)处理点云数据,无论是做三维重建、自动驾驶感知,还是机器人导航,有一个工具你几乎无法绕开,那就是KdTree。它不像点云滤波、配准那样有直观的视觉效果&…

2026/7/17 5:58:40 阅读更多 →
C++结构体从入门到精通:语法、内存对齐与实战应用

C++结构体从入门到精通:语法、内存对齐与实战应用

1. 为什么C程序员绕不开结构体?如果你刚开始学C,可能觉得数组已经够用了,它能存一堆相同类型的数据。但当你真正开始写点像样的程序,比如要管理一个学生信息(姓名、学号、成绩),或者处理一个坐标…

2026/7/17 5:56:39 阅读更多 →
Python代码硬件绑定保护实战:使用PyArmor实现一机一码授权

Python代码硬件绑定保护实战:使用PyArmor实现一机一码授权

1. 项目概述与核心价值最近在和一些做软件交付的朋友聊天,发现一个共同的痛点:辛辛苦苦用Python开发的脚本或者工具,发给客户后,对方转手就复制给了别人,甚至直接反编译了你的核心逻辑。尤其是在一些涉及算法、数据处理…

2026/7/17 5:56:39 阅读更多 →
Windows 11官方纯净版安装与优化全指南

Windows 11官方纯净版安装与优化全指南

1. Windows 11官方纯净版安装全流程解析在微软停止Win10支持倒计时的背景下,越来越多的用户开始转向Windows 11。但市面上充斥着各种魔改版系统镜像,不仅捆绑流氓软件,还可能存在后门风险。作为从业十余年的系统工程师,我将完整演…

2026/7/17 5:56:39 阅读更多 →
Copilot、Cursor与JetBrains AI实战选型指南

Copilot、Cursor与JetBrains AI实战选型指南

1. 2026年的真实战场:不是“选哪个”,而是“用什么场景打什么仗”2026年了,当“AI编程工具”这个词已经从技术圈热词变成团队周会里的常规议题,再问“Copilot还是Cursor”,就像在问“用锤子还是螺丝刀”——问题本身已…

2026/7/17 5:54:38 阅读更多 →
Node.js文件加密实战:基于Crypto与fs-extra的AES-256-GCM实现

Node.js文件加密实战:基于Crypto与fs-extra的AES-256-GCM实现

1. 项目概述:为什么我们需要在Node.js中加密文件?在开发后端服务或桌面应用时,我们常常需要处理用户上传的敏感文件,比如合同、身份证明、财务报告,或是应用自身的配置文件。直接将这些文件以明文形式存储在磁盘上&…

2026/7/17 5:52:38 阅读更多 →

日新闻

2026全国外贸独立站搭建公司推荐排行,含零代码SAAS、AI编程、源码定制

2026全国外贸独立站搭建公司推荐排行,含零代码SAAS、AI编程、源码定制

2026全国外贸独立站搭建公司推荐排行 外贸工厂、工贸企业建设官网,核心需求与普通展示型网站并不相同。除了页面整洁、多语言适配和海外访问体验,企业还要重点考虑数据能否导出、站点能否迁移、源码是否可控、后续费用是否透明,以及更换服务…

2026/7/17 0:02:10 阅读更多 →
HarmonyOS 应用开发《掌上英语》第19篇:3D 翻转动画实现——ArkTS 动画系统全解析

HarmonyOS 应用开发《掌上英语》第19篇:3D 翻转动画实现——ArkTS 动画系统全解析

3D 翻转动画实现——ArkTS 动画系统全解析引言 在移动应用中,卡片翻转动画是最受欢迎的交互动效之一,它能给用户带来直观的"物理世界"操作感。在我们的英语学习 App 的单词学习页面(CourseHomePage.ets)中,就…

2026/7/17 0:02:10 阅读更多 →
2026键盘推荐|IQUNIX EV63多场景适配,不允许有人不知道!

2026键盘推荐|IQUNIX EV63多场景适配,不允许有人不知道!

现在很多用户都需要一款能适配多场景的键盘,既能满足交流码字的需求,又能应对居家电竞的性能需求,最好还得有点小颜值。而大多键盘都只能兼顾其中一两个场景。这次我实测了IQUNIX EV63三款配色(银武士、黑武士、紫罗兰&#xff09…

2026/7/17 0:04:10 阅读更多 →

周新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/17 3:22:28 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/17 3:01:28 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/16 23:40:37 阅读更多 →

月新闻