HarmonyOS开发实战—如何实现应用悬浮窗

本文主要介绍如何利用应用子窗口实现应用内全局悬浮窗,创建应用子窗口需要先拿到窗口管理器 WindowStage 对象,在 EntryAbility.onWindowStageCreate() 回调中取。

复制代码
FloatManager.init(windowStage)
init(windowStage: window.WindowStage) {
  this.windowStage_ = windowStage
}

然后通过 WindowStage.createSubWindow() 创建子窗口。

复制代码
// 创建子窗口
showSubWindow() {
    if (this.windowStage_ == null) {
        Log.error(TAG, 'Failed to create the subwindow. Cause: windowStage_ is null');
    } else {
        this.windowStage_.createSubWindow("HarmonyWorld", (err: BusinessError, data) => {
            ...
            this.sub_windowClass = data;
            // 子窗口创建成功后,设置子窗口的位置、大小及相关属性等
            // moveWindowTo 和 resize 都可以重复调用,实现拖拽效果
            this.sub_windowClass.moveWindowTo(this.locationX, this.locationY, (err: BusinessError) => {
                ...
            });
            this.sub_windowClass.resize(this.size, this.size, (err: BusinessError) => {
                ...
            });
            // 给子窗口设置内容
            this.sub_windowClass.setUIContent("pages/float/FloatPage", (err: BusinessError) => {
                ...
                // 显示子窗口。
                (this.sub_windowClass as window.Window).showWindow((err: BusinessError) => {
                    ...
                    // 设置透明背景
                    data.setWindowBackgroundColor("#00000000")
                });
            });
        })
    }
}

这样就可以在指定位置显示指定大小的的悬浮窗了。然后再接着完善手势拖动和点击事件。

既要监听拖动,又要监听手势,就需要通过 GestoreGroup,并把设置模式设置为 互斥识别

复制代码
@Entry
@Component
export struct FloatPage {
  private context = getContext(this) as common.UIAbilityContext
  build() {
    Column() {
      Image($r('app.media.mobile_dev'))
        .width('100%')
        .height('100%')
    }
    .gesture(
      GestureGroup(GestureMode.Exclusive,
        // 监听拖动
        PanGesture()
          .onActionUpdate((event: GestureEvent | undefined) => {
            if (event) {
              // 更新悬浮窗位置
              FloatManager.updateLocation(event.offsetX, event.offsetY)
            }
          }),
        // 监听点击
        TapGesture({ count: 1 })
          .onAction(() => {
             router.pushUrl(...)
          }))
    )
  }
}

在拖动手势 PanGesture 的 onActionUpdate() 回调中,可以实时拿到拖动的距离,然后通过 Window.moveWindowTo() 就可以实时更新悬浮窗的位置了。

复制代码
updateLocation(offSetX: number, offsetY: number) {
    if (this.sub_windowClass != null) {
        this.locationX = this.locationX + offSetX
        this.locationY = this.locationY + offsetY
        this.sub_windowClass.moveWindowTo(this.locationX, this.locationY, (err: BusinessError) => {
            ......
        });
    }
}

在点击手势 TapGesture中,我的需求是路由到指定页面,直接调用 router.pushUrl()。看似很正常的调用,在这里确得到了意想不到的结果。

每个 Window 对应自己的 UIContext,UIContext 持有自己的 Router ,所以应用主窗口和应用子窗口的 Router 是相互独立的。

那么,问题就变成了如何在子窗口中让主窗口进行路由跳转?通过 EventHub 或者 emitter 都可以。emiiter 可以跨线程,这里并不需要,EventHub 写起来更简单。我们在点击手势中发送事件:

复制代码
TapGesture({ count: 1 })
  .onAction(() => {
      this.context.eventHub.emit("event_click_float")
  })

在 EntryAbility 中订阅事件:

复制代码
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    eventHub.on("event_click_float", () => {
      if (this.mainRouter) {
        this.mainRouter.pushUrl(...)
      }
    })
}

这里的 mainRouter 我们可以提前在主 Window 调用 loadContent() 之后获取:

复制代码
windowStage.loadContent(pages/Index', (err, data) => {
  this.mainRouter = this.windowClass!.getUIContext().getRouter()
});

最后还有一个小细节,如果在拖动悬浮窗之后,再使用系统的返回手势,按照预期应该是主窗口的页面返回,但这时候焦点在子窗口,主窗口并不会响应返回手势。

我们需要在子窗口承载的 Page 页面监听 onBackPress(),并通过 EventHub 通知主窗口。

复制代码
onBackPress(): boolean | void {
    this.context.eventHub.emit("float_back")
  }

主窗口接收到通知后,调用 mainRouter.back 。

复制代码
eventHub.on("clickFloat", () => {
  if (this.mainRouter) {
    this.mainRouter.back()
  }
})

应用内全局,可拖拽的悬浮窗就完成了。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了几套最新版的HarmonyOS NEXT学习资源

获取完整版高清学习路线,请点击→《HarmonyOS教学视频

HarmonyOS教学视频

鸿蒙语法ArkTS、TypeScript、ArkUI等.....视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取白皮书:请点击→《鸿蒙生态应用开发白皮书V2.0PDF

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. ......

二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全
  5. ........

三、如何快速入门?《鸿蒙星河版开发教程指南

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ......

四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ......

五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ......

更多了解更多鸿蒙开发的相关知识可以参考: 鸿蒙 (Harmony OS)开发学习手册

相关推荐
zhanshuo6 小时前
鸿蒙应用调试与测试实战全指南:高效定位问题,性能优化必备技巧+实用代码示例
harmonyos
万少10 小时前
2025中了 聊一聊程序员为什么都要做自己的产品
前端·harmonyos
网络小白不怕黑11 小时前
华为设备 QoS 流分类与流标记深度解析及实验脚本
网络·华为
网络小白不怕黑11 小时前
华为交换机堆叠与集群技术深度解析附带脚本
网络·华为
幽蓝计划1 天前
HarmonyOS NEXT仓颉开发语言实战案例:动态广场
华为·harmonyos
万少1 天前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
幽蓝计划1 天前
HarmonyOS NEXT仓颉开发语言实战案例:电影App
华为·harmonyos
HMS Core1 天前
HarmonyOS免密认证方案 助力应用登录安全升级
安全·华为·harmonyos
生如夏花℡1 天前
HarmonyOS学习记录3
学习·ubuntu·harmonyos
jie_07541 天前
鸿蒙系统(HarmonyOS)4.2 设备上实现无线安装 APK 并调试
华为·harmonyos