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)开发学习手册

相关推荐
沈剑心7 小时前
如何在鸿蒙系统上实现「沉浸式」页面?
前端·harmonyos
Georgewu8 小时前
【HarmonyOS】鸿蒙应用加载读取csv文件
前端·harmonyos
Georgewu8 小时前
【HarmonyOS】 鸿蒙图片或视频保存相册
前端·harmonyos
准橙考典12 小时前
如何考驾照?
物联网·安全·华为·自动驾驶·汽车
川石教育14 小时前
鸿蒙开发-ArkTS 中使用 filter 组件
harmonyos·鸿蒙·鸿蒙应用开发·鸿蒙开发·鸿蒙开发培训·arkts语言
李洋-蛟龙腾飞公司14 小时前
HarmonyOS Next 应用元服务开发-分布式数据对象迁移数据权限与基础数据
分布式·华为·harmonyos
Damon小智14 小时前
HarmonyOS NEXT 技术实践-实现音乐服务卡片
华为·harmonyos·鸿蒙·harmonyos next·服务卡片
play_big_knife14 小时前
鸿蒙项目云捐助第十七讲云捐助我的页面上半部分的实现
华为·harmonyos·鸿蒙·云开发·鸿蒙开发·鸿蒙next·华为云开发
枫叶丹420 小时前
【HarmonyOS之旅】HarmonyOS开发基础知识(三)
华为od·华为·华为云·harmonyos
SoraLuna1 天前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos