1.准备工作 entryAbility中  暂存主窗口对象

onWindowStageCreate(windowStage: window.WindowStage): void {
  //组件间通信 -- 主窗口
  AppStorage.setOrCreate('windowStage',windowStage)
  // ...
}

2.封装悬浮球的初始化,创建一个系统util文件.ets

export class SubWindow{
  static createFloatWindow() {
    //拿到主窗口
    let windowStage = AppStorage.get("windowStage") as window.WindowStage;
    // 在主窗口上创建子窗口 floatWindow
    windowStage.createSubWindow("floatWindow", (err, subWin) => {
      if (err.code) {
        return;
      }
      // 设置悬浮窗位置
      subWin.moveWindowTo(vp2px(255), vp2px(120), (err) => {
        if (err.code) {
          return;
        }
      });
      // 设置悬浮窗大小
      subWin.resize(vp2px(100), vp2px(100), (err) => {
        if (err.code) {
          return;
        }
      });
      // 为悬浮窗加载页面内容,这里可以设置在main_pages.json中配置的页面(主入口页面路由)
      subWin.setUIContent('pages/LevitatedSphere', (err) => {
        if (err.code) {
          return;
        }
        //设置悬浮窗背景色
        subWin.setWindowBackgroundColor("#00000000")
        // 显示悬浮窗。
        subWin.showWindow((err) => {
          if (err.code) {
            return;
          }
        });
      });

    });
  }
}

3.配置悬浮球的UI结构和逻辑

window.shiftAppWindowFocus()这个方法很重要,需要配置好这个方法,否则主窗口和子窗口展示内容会发生混乱

//LevitatedSphere页面,悬浮球UI页面
windowStage = AppStorage.get("windowStage") as window.WindowStage;//主窗口

async aboutToAppear(){
  let subWindowID:number = window.findWindow('floatWindow').getWindowProperties().id
  let mainWindowID:number = this.windowStage.getMainWindowSync().getWindowProperties().id
  //在同应用内,将窗口焦点从源窗口转移到目标窗口,仅支持应用主窗和子窗的焦点转移
  await window.shiftAppWindowFocus(subWindowID,mainWindowID)
  
  //设置子窗口的显示方向,竖屏
  this.floatWindow.setPreferredOrientation(window.Orientation.LANDSCAPE)
 }
 
 async onPageShow(){
  let subWindowID:number = window.findWindow('floatWindow').getWindowProperties().id
  let mainWindowID:number = this.windowStage.getMainWindowSync().getWindowProperties().id
  await window.shiftAppWindowFocus(subWindowID,mainWindowID)
 }

build() {
  Column(){
    Image($r('app.media.sxi_text')).width(100)
    Image($r('app.media.sxi_xf')).width(48)
  }
  .height(100)
  .onClick(()=>{
    //悬浮球点击事件,触发emitter
    let event: emitter.InnerEvent = {
      eventId: 33999
    };
    emitter.emit(event)
  })
}

4.使用悬浮球

//应用的首页
async aboutToAppear() {
  //创建悬浮窗
  SubWindow.createFloatWindow()
  
  let event: emitter.InnerEvent = {
  eventId: 33999
  };
  emitter.on(event, () => {
  const emitterCount = emitter.getListenerCount(33999)
  //如果有多个监听,需要销毁监听,避免逻辑重复触发
  if (emitterCount !== 1) {
    emitter.off(33999)
  }
  //点击悬浮球后需要执行的逻辑
  router.pushUrlByName()
  })
}

5.拖动悬浮球

//LevitatedSphere页面
//创建平移手势识别器对象
private panOption:PanGestureOptions = new PanGestureOptions({ direction:PanDirection.All })  //所有方向都可以识别
//悬浮窗的初始位置信息并开启监听
@State @Watch("moveWindow") windowPosition: Position = { x: vp2px(255), y: vp2px(120) };
//找到子窗口
floatWindow :window.Window = window.findWindow('floatWindow')  //查找name所对应的窗口。
moveWindow(){
  this.floatWindow.moveWindowTo(Number(this.windowPosition.x), Number(this.windowPosition.y));
}

Column(){
  Image($r('app.media.sxi_text')).width(100)
  Image($r('app.media.sxi_xf')).width(48)
}
.height(100)
.onClick(()=>{
  let event: emitter.InnerEvent = {
    eventId: 33999
  };
  emitter.emit(event)
})
.gesture(   //给column绑定手势事件
  //绑定手势事件
  PanGesture(this.panOption)
    .onActionStart((event)=>{
      //手势绑定成功
    })
    .onActionUpdate((event)=>{
      //发生拖拽时,获取到拖拽信息
      this.windowPosition.x += event.offsetX;
      this.windowPosition.y += event.offsetY;
    })
    .onActionEnd(() => {
      //手势绑定成功,回调结束时触发
    })
)

6.隐藏/显示悬浮窗

minimize()

1.当调用对象为主窗口时,实现最小化功能,可在Dock栏中还原。

2.当调用对象为子窗口时,实现隐藏功能,不可在Dock栏中还原,可以使用showWindow()进行还原。

const floatWindow= window.findWindow('floatWindow')
if (this.currentIndex === 0) {
  //首页隐藏悬浮窗
  floatWindow.minimize()
}else{
  //其他页面显示悬浮球
  floatWindow.showWindow()
}

7.特殊场景隐藏悬浮球(如果是组件没有onPageShow的话,可以使用watch监听触发隐藏子窗口)

onPageShow(): void {
  //隐藏子窗口
  const subWindow = window.findWindow('floatWindow')
  subWindow.minimize()
}

onPageHide(): void {
  //打开子窗口
  const subWindow = window.findWindow('floatWindow')
  subWindow.showWindow()
}

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐