99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

鴻蒙實(shí)戰(zhàn)開(kāi)發(fā):【實(shí)現(xiàn)應(yīng)用懸浮窗】

jf_46214456 ? 來(lái)源:jf_46214456 ? 作者:jf_46214456 ? 2024-04-03 22:18 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

如果你要做的是系統(tǒng)級(jí)別的懸浮窗,就需要判斷是否具備懸浮窗權(quán)限。然而這又不是一個(gè)標(biāo)準(zhǔn)的動(dòng)態(tài)權(quán)限,你需要兼容各種奇葩機(jī)型的懸浮窗權(quán)限判斷,下面的代碼來(lái)自于某著名開(kāi)源庫(kù):EasyFloat[1] 。

fun checkPermission(context: Context): Boolean =
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) when {
    RomUtils.checkIsHuaweiRom() - > huaweiPermissionCheck(context)
    RomUtils.checkIsMiuiRom() - > miuiPermissionCheck(context)
    RomUtils.checkIsOppoRom() - > oppoROMPermissionCheck(context)
    RomUtils.checkIsMeizuRom() - > meizuPermissionCheck(context)
    RomUtils.checkIs360Rom() - > qikuPermissionCheck(context)
            else - > true
} else commonROMPermissionCheck(context)

private fun commonROMPermissionCheck(context: Context): Boolean =
        if (RomUtils.checkIsMeizuRom()) meizuPermissionCheck(context) else {
            var result = true
            if (Build.VERSION.SDK_INT >= 23) try {
                val clazz = Settings::class.java
                val canDrawOverlays = clazz.getDeclaredMethod("canDrawOverlays", Context::class.java)
                result = canDrawOverlays.invoke(null, context) as Boolean
            } catch (e: Exception) {
                Log.e(TAG, Log.getStackTraceString(e))
            }
            result
        }

如果你要做的是應(yīng)用內(nèi)的全局懸浮窗,那么對(duì)不起,不支持,自己想辦法。普遍的做法是在根布局 DecorView 直接塞進(jìn)去。

遙遙領(lǐng)先qr23.cn/AKFP8k獲取

.png

或者加mau123789是v直接領(lǐng)??!

鴻蒙上實(shí)現(xiàn)懸浮窗相對(duì)就要簡(jiǎn)單的多。

對(duì)于系統(tǒng)級(jí)別彈窗,仍然需要權(quán)限,但也不至于那么麻煩的適配。

對(duì)于應(yīng)用內(nèi)全局彈出,鴻蒙提供了 應(yīng)用子窗口 可以直接實(shí)現(xiàn)。

本文主要介紹如何利用應(yīng)用子窗口實(shí)現(xiàn)應(yīng)用內(nèi)全局懸浮窗。

創(chuàng)建應(yīng)用子窗口需要先拿到窗口管理器 WindowStage 對(duì)象,在 EntryAbility.onWindowStageCreate() 回調(diào)中取。

FloatManager.init(windowStage)

init(windowStage: window.WindowStage) {
  this.windowStage_ = windowStage
}

然后通過(guò) WindowStage.createSubWindow() 創(chuàng)建子窗口。

// 創(chuàng)建子窗口
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;
            // 子窗口創(chuàng)建成功后,設(shè)置子窗口的位置、大小及相關(guān)屬性等
            // moveWindowTo 和 resize 都可以重復(fù)調(diào)用,實(shí)現(xiàn)拖拽效果
            this.sub_windowClass.moveWindowTo(this.locationX, this.locationY, (err: BusinessError) = > {
                ...
            });
            this.sub_windowClass.resize(this.size, this.size, (err: BusinessError) = > {
                ...
            });
            // 給子窗口設(shè)置內(nèi)容
            this.sub_windowClass.setUIContent("pages/float/FloatPage", (err: BusinessError) = > {
                ...
                // 顯示子窗口。
                (this.sub_windowClass as window.Window).showWindow((err: BusinessError) = > {
                    ...
                    // 設(shè)置透明背景
                    data.setWindowBackgroundColor("#00000000")
                });
            });
        })
    }
}

這樣就可以在指定位置顯示指定大小的的懸浮窗了。

然后再接著完善手勢(shì)拖動(dòng)和點(diǎn)擊事件。

既要監(jiān)聽(tīng)拖動(dòng),又要監(jiān)聽(tīng)手勢(shì),就需要通過(guò) GestoreGroup,并把設(shè)置模式設(shè)置為 互斥識(shí)別 。

@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,
        // 監(jiān)聽(tīng)拖動(dòng)
        PanGesture()
          .onActionUpdate((event: GestureEvent | undefined) = > {
            if (event) {
              // 更新懸浮窗位置
              FloatManager.updateLocation(event.offsetX, event.offsetY)
            }
          }),
        // 監(jiān)聽(tīng)點(diǎn)擊
        TapGesture({ count: 1 })
          .onAction(() = > {
             router.pushUrl(...)
          }))
    )
  }
}

在拖動(dòng)手勢(shì) PanGestureonActionUpdate() 回調(diào)中,可以實(shí)時(shí)拿到拖動(dòng)的距離,然后通過(guò) Window.moveWindowTo() 就可以實(shí)時(shí)更新懸浮窗的位置了。

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) = > {
            ......
        });
    }
}

在點(diǎn)擊手勢(shì) TapGesture中,我的需求是路由到指定頁(yè)面,直接調(diào)用 router.pushUrl()??此坪苷5恼{(diào)用,在這里確得到了意想不到的結(jié)果。

發(fā)生頁(yè)面跳轉(zhuǎn)的并不是預(yù)期中的應(yīng)用主窗口,而是應(yīng)用子窗口。

把問(wèn)題拋到群里之后,得到了群友的熱心解答。

每個(gè) Window 對(duì)應(yīng)自己的 UIContext,UIContext 持有自己的 Router ,所以應(yīng)用主窗口和應(yīng)用子窗口的 Router 是相互獨(dú)立的。

那么,問(wèn)題就變成了如何在子窗口中讓主窗口進(jìn)行路由跳轉(zhuǎn)?通過(guò) EventHub 或者 emitter 都可以。emiiter 可以跨線程,這里并不需要,EventHub 寫起來(lái)更簡(jiǎn)單。我們?cè)邳c(diǎn)擊手勢(shì)中發(fā)送事件:

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 調(diào)用 loadContent() 之后獲?。?/p>

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

最后還有一個(gè)小細(xì)節(jié),如果在拖動(dòng)懸浮窗之后,再使用系統(tǒng)的返回手勢(shì),按照預(yù)期應(yīng)該是主窗口的頁(yè)面返回,但這時(shí)候焦點(diǎn)在子窗口,主窗口并不會(huì)響應(yīng)返回手勢(shì)。

我們需要在子窗口承載的 Page 頁(yè)面監(jiān)聽(tīng) onBackPress(),并通過(guò) EventHub 通知主窗口。

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

主窗口接收到通知后,調(diào)用 mainRouter.back 。

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

應(yīng)用內(nèi)全局,可拖拽的懸浮窗就完成了。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 鴻蒙
    +關(guān)注

    關(guān)注

    60

    文章

    2620

    瀏覽量

    44063
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    鴻蒙5開(kāi)發(fā)寶藏案例分享---一多開(kāi)發(fā)實(shí)例(音樂(lè))

    各位開(kāi)發(fā)者小伙伴們好呀!今天咱們來(lái)點(diǎn)硬核干貨!最近在鴻蒙文檔中心挖到一座“金礦”——官方竟然暗藏了100+實(shí)戰(zhàn)案例,從分布式架構(gòu)到交互動(dòng)效優(yōu)化應(yīng)有盡有!這些案例不僅藏著華為工程師的私房技巧,還直接
    的頭像 發(fā)表于 06-30 11:54 ?345次閱讀

    HarmonyOS實(shí)戰(zhàn)實(shí)現(xiàn)任意拖動(dòng)的應(yīng)用懸浮窗口

    為了增加應(yīng)用程序功能的豐富性和便利性,很多應(yīng)用都會(huì)提供一個(gè)懸浮窗口實(shí)現(xiàn)多頁(yè)面顯示。特別是一些性能檢測(cè)工具,比如 dokit 。在鴻蒙上怎么實(shí)現(xiàn)類似的全局
    的頭像 發(fā)表于 06-24 17:04 ?644次閱讀

    鴻蒙5開(kāi)發(fā)寶藏案例分享---埋點(diǎn)開(kāi)發(fā)實(shí)戰(zhàn)指南

    鴻蒙埋點(diǎn)開(kāi)發(fā)寶藏指南:官方案例實(shí)戰(zhàn)解析,輕松搞定數(shù)據(jù)追蹤! 大家好呀!我是HarmonyOS開(kāi)發(fā)路上的探索者。最近在折騰應(yīng)用埋點(diǎn)時(shí),意外發(fā)現(xiàn)了鴻蒙
    發(fā)表于 06-12 16:30

    鴻蒙5開(kāi)發(fā)寶藏案例分享---切面編程實(shí)戰(zhàn)揭秘

    鴻蒙切面編程(AOP)實(shí)戰(zhàn)指南:隱藏的寶藏功能大揭秘! 大家好!今天在翻鴻蒙開(kāi)發(fā)者文檔時(shí),意外發(fā)現(xiàn)了官方埋藏的「切面編程」寶藏案例!實(shí)際開(kāi)發(fā)
    發(fā)表于 06-12 16:21

    鴻蒙5開(kāi)發(fā)寶藏案例分享---平板開(kāi)發(fā)實(shí)踐

    以下是根據(jù)官方文檔整理的鴻蒙平板開(kāi)發(fā)實(shí)戰(zhàn)指南,結(jié)合代碼解析和避坑要點(diǎn),幫你高效實(shí)現(xiàn)“一次開(kāi)發(fā),多端部署”? 一、開(kāi)篇:為什么平板
    發(fā)表于 06-12 15:49

    鴻蒙5開(kāi)發(fā)寶藏案例分享---Pura X開(kāi)發(fā)案例分享

    ?** 鴻蒙寶藏案例分享:Pura X 外屏開(kāi)發(fā)實(shí)戰(zhàn)解析** 大家好!我是你們的鴻蒙開(kāi)發(fā)小伙伴。今天在翻閱官方文檔時(shí),意外發(fā)現(xiàn)了華為藏著的\
    發(fā)表于 06-12 11:47

    鴻蒙5開(kāi)發(fā)寶藏案例分享---一多開(kāi)發(fā)實(shí)例(游戲)

    ?【開(kāi)發(fā)者必看】鴻蒙隱藏寶箱大公開(kāi)!這些實(shí)戰(zhàn)案例讓你的開(kāi)發(fā)效率翻倍! 哈嘍各位開(kāi)發(fā)者小伙伴!今天要和大家分享一個(gè)讓我拍大腿的發(fā)現(xiàn)——原來(lái)
    發(fā)表于 06-03 18:22

    鴻蒙5開(kāi)發(fā)案例分享揭秘---一多開(kāi)發(fā)實(shí)例(商務(wù)辦公)

    ?【鴻蒙開(kāi)發(fā)寶藏案例大揭秘】原來(lái)官方文檔里藏了這么多好東西! 大家好呀~最近在肝鴻蒙項(xiàng)目時(shí)意外扒出了官方文檔里的\"藏寶庫(kù)\"!原來(lái)那些讓人頭禿的跨端適配難題,官方早就準(zhǔn)備好
    發(fā)表于 06-03 16:24

    鴻蒙5開(kāi)發(fā)寶藏案例分享---一多開(kāi)發(fā)實(shí)例(地圖導(dǎo)航)

    ? 鴻蒙開(kāi)發(fā)隱藏寶藏大公開(kāi)!手把手教你玩轉(zhuǎn)\"一多\"地圖導(dǎo)航案例 ? 大家好呀!我是你們的老朋友,今天要給大家扒一扒鴻蒙官方文檔里那些\"藏得深\"的實(shí)戰(zhàn)
    發(fā)表于 06-03 16:17

    鴻蒙5開(kāi)發(fā)寶藏案例分享---一多開(kāi)發(fā)實(shí)例(購(gòu)物比價(jià))

    者文檔里的實(shí)戰(zhàn)教程,簡(jiǎn)直就是搞定多端開(kāi)發(fā)的通關(guān)秘籍! ? 一、這些功能也太酷了吧! 這個(gè)案例完美詮釋了鴻蒙\"一次開(kāi)發(fā),多端部署\"的超能力,這些神仙功能你一定要知道: 智能分屏比價(jià)
    發(fā)表于 06-03 16:07

    鴻蒙5開(kāi)發(fā)寶藏案例分享---一多分欄開(kāi)發(fā)實(shí)踐

    ?【HarmonyOS開(kāi)發(fā)者的寶藏指南】一次搞定多設(shè)備分欄布局,原來(lái)還能這么玩! 大家好呀!今天在鴻蒙社區(qū)挖到一個(gè)超實(shí)用的大寶藏——原來(lái)官方早就藏了一堆分欄布局的實(shí)戰(zhàn)案例!作為被多端適配折磨
    發(fā)表于 06-03 12:03

    鴻蒙Flutter實(shí)戰(zhàn):14-現(xiàn)有Flutter 項(xiàng)目支持鴻蒙 II

    分別安裝官方的3.22版本,以及鴻蒙社區(qū)的 3.22.0 版本 3.搭建 Flutter鴻蒙開(kāi)發(fā)環(huán)境 參考文章《鴻蒙Flutter實(shí)戰(zhàn):0
    發(fā)表于 12-26 14:59

    鴻蒙Flutter實(shí)戰(zhàn):11-使用 Flutter SDK 3.22.0

    # 使用 Flutter SDK 3.22.0 ## SDK 安裝 參考[鴻蒙Flutter實(shí)戰(zhàn):01-搭建開(kāi)發(fā)環(huán)境]文章的說(shuō)明,首先安裝 Flutter SDK 3.22.0。 目前
    發(fā)表于 11-01 15:03

    鴻蒙Flutter實(shí)戰(zhàn):08-如何調(diào)試代碼

    # 鴻蒙Flutter實(shí)戰(zhàn):如何調(diào)試代碼 ## 1.環(huán)境搭建 參考文章[鴻蒙Flutter實(shí)戰(zhàn):01-搭建開(kāi)發(fā)環(huán)境](https://g
    發(fā)表于 10-23 16:29

    鴻蒙Flutter實(shí)戰(zhàn):07混合開(kāi)發(fā)

    # 鴻蒙Flutter實(shí)戰(zhàn):混合開(kāi)發(fā) 鴻蒙Flutter混合開(kāi)發(fā)主要有兩種形式。 ## 1.基于har 將flutter module
    發(fā)表于 10-23 16:00