鴻蒙6組件:閃控球

閃控球是一種在設(shè)備屏幕上懸浮的非全屏應(yīng)用窗口,為應(yīng)用提供臨時(shí)的全局能力,完成跨應(yīng)用交互。應(yīng)用可以將關(guān)鍵信息以小窗(閃控球)模式呈現(xiàn)。切換為小窗(閃控球)模式后,用戶可以進(jìn)行其他界面操作,提升使用體驗(yàn)。

演示

演示.gif

使用限制

1.API 20開始,支持使用閃控球能力
2.需要具有ohos.permission.USE_FLOAT_BALL權(quán)限
3.同一個(gè)應(yīng)用只能啟動一個(gè)閃控球,同一個(gè)設(shè)備最多同時(shí)存在兩個(gè)閃控球,超出覆蓋舊的
4.目前僅支持手機(jī)和平板設(shè)備
5.支持在DevEco Studio 6.0.1 Release及以上版本的模擬器中使用閃控球相關(guān)功能。

啟動和更新閃控球的配置參數(shù)FloatingBallParams

名稱 說明
template 閃控球模板
title 閃控球標(biāo)題
content 閃控球內(nèi)容
backgroundColor 閃控球背景顏色
icon 閃控球圖標(biāo)

支持模板

閃控球模板類型的枚舉FloatingBallTemplate目前支持四種閃控球模板布局

名稱 布局 說明 必傳參數(shù)
STATIC 靜態(tài)布局 支持標(biāo)題和圖標(biāo) title、icon
NORMAL 普通文本布局 支持標(biāo)題和內(nèi)容 title
EMPHATIC 強(qiáng)調(diào)文本布局 支持圖標(biāo)、標(biāo)題和內(nèi)容 title
SIMPLE 純文本布局 只支持標(biāo)題 title

閃控球控制器FloatingBallController

方法 說明
startFloatingBall(params: FloatingBallParams): Promise<void> 啟動閃控球
updateFloatingBall(params: FloatingBallParams): Promise<void> 更新閃控球
stopFloatingBall(): Promise<void> 停止閃控球
on(type: 'stateChange', callback: Callback<FloatingBallState>): void 監(jiān)聽生命周期狀態(tài)變化
off(type: 'stateChange', callback?: Callback<FloatingBallState>): void 取消監(jiān)聽
on(type: 'click', callback: Callback<void>): void 點(diǎn)擊監(jiān)聽事件
off(type: 'click', callback?: Callback<void>): void 取消監(jiān)聽
getFloatingBallWindowInfo(): Promise<FloatingBallWindowInfo> 獲得閃控球窗口信息
restoreMainWindow(want: Want): Promise<void> 恢復(fù)應(yīng)用主窗口并加載指定頁面

源碼

page

import { FloatingBallUtils } from '../utils/FloatingBallUtils'
import { MyNavigation } from '../utils/MyAttributeModifier'
import { image } from '@kit.ImageKit'
import { floatingBall } from '@kit.ArkUI'
import { WindowUtils } from '../utils/WindowUtils'
import { DateUtil } from '../utils/DateUtil'

@Entry
@ComponentV2
struct FloatingBallTest{
  pathStack : NavPathStack = new NavPathStack()
  ballIcon:image.PixelMap | undefined = FloatingBallUtils.getRawfilePixelMapSync('icon128.png')
  // 聲明閃控球控制器
  floatingBallController: floatingBall.FloatingBallController  | undefined = undefined
  private timerId: number = -1
  async aboutToAppear(): Promise<void> {
    if (!this.floatingBallController) {
      this.floatingBallController = await floatingBall.create({
        context: WindowUtils.getUIAbilityContext()
      })
    }
  }
  build() {
    Navigation(this.pathStack){
      Column({space:10}){
        Button('關(guān)閉').onClick(()=>{
          if (this.timerId > 0) {
            clearInterval(this.timerId)
            this.timerId = -1
          }
          FloatingBallUtils.onStopFloatingBall(this.floatingBallController)
        })
        Button('靜態(tài)布局').onClick(async ()=>{
          FloatingBallUtils.onCreateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.STATIC,()=>{},'靜態(tài)布局-標(biāo)題','內(nèi)容','',this.ballIcon)
        })
        Row({space:10}){
          Button('普通文本布局').onClick(async ()=>{
            FloatingBallUtils.onCreateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.NORMAL,()=>{},'普通文本布局-標(biāo)題','內(nèi)容','#0ae49d',this.ballIcon)
          })
          Button('更新').onClick(()=>{
            if (this.timerId > 0) {
              clearInterval(this.timerId)
              this.timerId = -1
            }
            this.timerId = setInterval(() => {
              FloatingBallUtils.onUpdateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.NORMAL,'時(shí)間',DateUtil.format(new Date().getTime(),'HH:mm:ss'),this.ballIcon)
            }, 1000)
          })
        }
        Button('強(qiáng)調(diào)文本布局').onClick(async ()=>{
          FloatingBallUtils.onCreateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.EMPHATIC,()=>{},'強(qiáng)調(diào)文本布局-標(biāo)題','內(nèi)容','#cc3217',this.ballIcon)
        })
        Button('純文本布局').onClick(async ()=>{
          FloatingBallUtils.onCreateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.SIMPLE,()=>{},'純文本布局-標(biāo)題','內(nèi)容','#4617cc',this.ballIcon)
        })
      }
    }
    .attributeModifier(new MyNavigation(this.pathStack))
  }
  aboutToDisappear() {
    if (this.timerId > 0) {
      clearInterval(this.timerId)
      this.timerId = -1
    }
    FloatingBallUtils.onStopFloatingBall(this.floatingBallController)
  }
}

FloatingBallUtils


// 該頁面提供工具類,展示閃控球的創(chuàng)建、更新、關(guān)閉邏輯
import image from '@ohos.multimedia.image';
import { BusinessError } from '@kit.BasicServicesKit';
import { floatingBall } from '@kit.ArkUI';
import { Want ,bundleManager  } from '@kit.AbilityKit';
import { WindowUtils } from './WindowUtils';

let BUNDLE_NAME: string=''
let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT;
try {
  bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => {
    BUNDLE_NAME = data.name
  }).catch((err: BusinessError) => {

  });
} catch (err) {
}

export class FloatingBallUtils {
  public static getRawfilePixelMapSync(path: string): image.PixelMap {
    try {
      const BUFFER = WindowUtils.getUIAbilityContext()!.resourceManager.getRawFileContentSync(path);
      const IMAGE_SOURCE: image.ImageSource = image.createImageSource(BUFFER.buffer as ArrayBuffer);
      return IMAGE_SOURCE.createPixelMapSync();
    } catch (e) {
      throw e as Error;
    }
  }

  // 閃控球啟動邏輯
  public static async onCreateFloatingBall(
    floatingBallController: floatingBall.FloatingBallController | undefined,
    template: floatingBall.FloatingBallTemplate,
    onActiveRowChange: (value: number) => void,  // 接收狀態(tài)更新回調(diào)函數(shù)
    title: string,
    content?: string,
    backgroundColor: string = '#ffffff',
    icon?: image.PixelMap): Promise<void> {
    // 注冊 監(jiān)聽點(diǎn)擊回調(diào)事件
    floatingBallController?.on('click', () => {
      let want: Want = {
        bundleName: BUNDLE_NAME,
        abilityName: 'EntryAbility'
      }
      // 使用promise異步回調(diào)
      floatingBallController?.restoreMainWindow(want)
        .then(() => {
        }).catch((err: BusinessError) => {
      })
    })
    // 注冊 監(jiān)聽狀態(tài)變化事件
    floatingBallController?.on('stateChange',
      (state: floatingBall.FloatingBallState) => {
        if(state === floatingBall.FloatingBallState.STOPPED) {
          floatingBallController?.off('click')
          floatingBallController?.off('stateChange')
          floatingBallController = undefined;
          // 執(zhí)行狀態(tài)更新回調(diào)
          onActiveRowChange?.(-1);
        }
      })
    // 最后啟動閃控球
    let startParams: floatingBall.FloatingBallParams = icon? {
      template: template,
      title: title,
      content: content,
      backgroundColor: backgroundColor,
      icon: icon
    } : {
      template: template,
      title: title,
      content: content,
      backgroundColor: backgroundColor
    }
    try {
      floatingBallController?.startFloatingBall(startParams)
        .then(() => {
          console.log(`succeed in starting FloatingBall`)
        }).catch((err: BusinessError) => {
        console.error(`failed to start FloatingBall. code: ${err.code}, message: ${err.message}`)
      })
    } catch (e) {
      console.error('startFloatingBall Error', e)
    }
  }

  // 閃控球更新邏輯
  public static onUpdateFloatingBall(
    floatingBallController: floatingBall.FloatingBallController | undefined,
    template: floatingBall.FloatingBallTemplate,
    title: string,
    content?: string ,
    icon?: image.PixelMap): void {
    let updateParams: floatingBall.FloatingBallParams = icon ? {
      template: template,
      title: title,
      content: content,
      backgroundColor: '#ffffff',
      icon: icon
    } : {
      template: template,
      title: title ,
      content: content,
      backgroundColor: '#ffffff',
    }
    try {
      floatingBallController?.updateFloatingBall(updateParams).then(() => {
      }).catch((err: BusinessError) => {
        console.error('updateFloatingBall Error:', err)
      })
    } catch (e) {
      console.error('updateFloatingBall Error:', e)
    }
  }

  // 閃控球停止邏輯
  public static onStopFloatingBall(floatingBallController: floatingBall.FloatingBallController | undefined): void {
    // stop 是異步流程,需要通過 stateChange 狀態(tài)回調(diào)獲取實(shí)際刪除結(jié)果
    floatingBallController?.stopFloatingBall().then(() => {

    }).catch((err: BusinessError) => {
      console.error('stopFloatingBall Error:', err)
    })
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容