鸿蒙6组件:闪控球

闪控球是一种在设备屏幕上悬浮的非全屏应用窗口,为应用提供临时的全局能力,完成跨应用交互。应用可以将关键信息以小窗(闪控球)模式呈现。切换为小窗(闪控球)模式后,用户可以进行其他界面操作,提升使用体验。

演示

演示.gif

使用限制

1.API 20开始,支持使用闪控球能力
2.需要具有ohos.permission.USE_FLOAT_BALL权限
3.同一个应用只能启动一个闪控球,同一个设备最多同时存在两个闪控球,超出覆盖旧的
4.目前仅支持手机和平板设备
5.支持在DevEco Studio 6.0.1 Release及以上版本的模拟器中使用闪控球相关功能。

启动和更新闪控球的配置参数FloatingBallParams

名称 说明
template 闪控球模板
title 闪控球标题
content 闪控球内容
backgroundColor 闪控球背景颜色
icon 闪控球图标

支持模板

闪控球模板类型的枚举FloatingBallTemplate目前支持四种闪控球模板布局

名称 布局 说明 必传参数
STATIC 静态布局 支持标题和图标 title、icon
NORMAL 普通文本布局 支持标题和内容 title
EMPHATIC 强调文本布局 支持图标、标题和内容 title
SIMPLE 纯文本布局 只支持标题 title

闪控球控制器FloatingBallController

方法 说明
startFloatingBall(params: FloatingBallParams): Promise<void> 启动闪控球
updateFloatingBall(params: FloatingBallParams): Promise<void> 更新闪控球
stopFloatingBall(): Promise<void> 停止闪控球
on(type: 'stateChange', callback: Callback<FloatingBallState>): void 监听生命周期状态变化
off(type: 'stateChange', callback?: Callback<FloatingBallState>): void 取消监听
on(type: 'click', callback: Callback<void>): void 点击监听事件
off(type: 'click', callback?: Callback<void>): void 取消监听
getFloatingBallWindowInfo(): Promise<FloatingBallWindowInfo> 获得闪控球窗口信息
restoreMainWindow(want: Want): Promise<void> 恢复应用主窗口并加载指定页面

源码

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('关闭').onClick(()=>{
          if (this.timerId > 0) {
            clearInterval(this.timerId)
            this.timerId = -1
          }
          FloatingBallUtils.onStopFloatingBall(this.floatingBallController)
        })
        Button('静态布局').onClick(async ()=>{
          FloatingBallUtils.onCreateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.STATIC,()=>{},'静态布局-标题','内容','',this.ballIcon)
        })
        Row({space:10}){
          Button('普通文本布局').onClick(async ()=>{
            FloatingBallUtils.onCreateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.NORMAL,()=>{},'普通文本布局-标题','内容','#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,'时间',DateUtil.format(new Date().getTime(),'HH:mm:ss'),this.ballIcon)
            }, 1000)
          })
        }
        Button('强调文本布局').onClick(async ()=>{
          FloatingBallUtils.onCreateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.EMPHATIC,()=>{},'强调文本布局-标题','内容','#cc3217',this.ballIcon)
        })
        Button('纯文本布局').onClick(async ()=>{
          FloatingBallUtils.onCreateFloatingBall(this.floatingBallController,floatingBall.FloatingBallTemplate.SIMPLE,()=>{},'纯文本布局-标题','内容','#4617cc',this.ballIcon)
        })
      }
    }
    .attributeModifier(new MyNavigation(this.pathStack))
  }
  aboutToDisappear() {
    if (this.timerId > 0) {
      clearInterval(this.timerId)
      this.timerId = -1
    }
    FloatingBallUtils.onStopFloatingBall(this.floatingBallController)
  }
}

FloatingBallUtils


// 该页面提供工具类,展示闪控球的创建、更新、关闭逻辑
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,  // 接收状态更新回调函数
    title: string,
    content?: string,
    backgroundColor: string = '#ffffff',
    icon?: image.PixelMap): Promise<void> {
    // 注册 监听点击回调事件
    floatingBallController?.on('click', () => {
      let want: Want = {
        bundleName: BUNDLE_NAME,
        abilityName: 'EntryAbility'
      }
      // 使用promise异步回调
      floatingBallController?.restoreMainWindow(want)
        .then(() => {
        }).catch((err: BusinessError) => {
      })
    })
    // 注册 监听状态变化事件
    floatingBallController?.on('stateChange',
      (state: floatingBall.FloatingBallState) => {
        if(state === floatingBall.FloatingBallState.STOPPED) {
          floatingBallController?.off('click')
          floatingBallController?.off('stateChange')
          floatingBallController = undefined;
          // 执行状态更新回调
          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 状态回调获取实际删除结果
    floatingBallController?.stopFloatingBall().then(() => {

    }).catch((err: BusinessError) => {
      console.error('stopFloatingBall Error:', err)
    })
  }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容