鸿蒙next 子窗口实现悬浮球功能来了

前言:

最近要写鸿蒙手游sdk 要做悬浮球功能 就找了下资料,然后就写了下这个案例,那么废话不多少我们正式开始。

效果图:

我们可以通过点击显示和隐藏来控制悬浮球的显示和隐藏的情况

具体实现

悬浮球主体的布局和拖动效果

kotlin 复制代码
import { display, inspector, window } from '@kit.ArkUI';
import CommonConstants from '../constants/CommonConstants';
import Logger from '../utils/Logger';
import { WindowPosition } from '../viewmodel/WindowPosition';

@Entry
@Component
struct ResizeWindowPage {
  @State windowStage: window.WindowStage = AppStorage.get('windowStage') as window.WindowStage;
  @State subWindow: window.Window = window.findWindow('ResizeWindowPage');
  @State flag: boolean = true;
  @State windowPosition: WindowPosition = {
    x: CommonConstants.DEFAULT_WINDOW_X,
    y: CommonConstants.DEFAULT_WINDOW_Y
  };
  @StorageLink('screenWidth') screenWidth: number = 0;
  @StorageLink('screenHeight') screenHeight: number = 0;
  listener: inspector.ComponentObserver = inspector.createComponentObserver('COMPONENT_ID');
  private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All });
  private callback: () => void = () => {
    if (!this.flag) {
      this.subWindow.resize(vp2px(this.screenWidth * CommonConstants.WINDOW_COEFFICIENT),
        vp2px(this.screenHeight * CommonConstants.WINDOW_COEFFICIENT));
    } else {
      this.subWindow.resize(vp2px(CommonConstants.DEFAULT_WINDOW_SIZE),
        vp2px(CommonConstants.DEFAULT_WINDOW_SIZE));
    }
  };

  onPageShow(): void {
    setTimeout(() => {
      try {
        let subWindowID: number = window.findWindow('ResizeWindowPage').getWindowProperties().id;
        let mainWindowID: number = this.windowStage.getMainWindowSync().getWindowProperties().id;
        window.shiftAppWindowFocus(subWindowID, mainWindowID);
      } catch (error) {
        Logger.error('shiftAppWindowFocus failed' + JSON.stringify(error));
      }
    }, CommonConstants.TIME_DELAY)
    this.listener.on('layout', this.callback);
  }

  onPageHide(): void {
    this.listener.off('layout', this.callback);
  }

  /**
   * Move the floating window to the specified position.
   */
  moveWindow() {
    this.subWindow.moveWindowTo(this.windowPosition.x, this.windowPosition.y);
  }

  build() {
    Row() {
      Column() {
        //Image(this.flag ? $r('app.media.ic_public_video') : $r('app.media.ic_public_picture'))
        Image( $r('app.media.hemei_img_float'))
          .height(CommonConstants.FULL_PERCENT)
          .id('COMPONENT_ID')
          .borderRadius(16)
          .onClick(() => {
            //点击显示悬浮窗球
            //this.flag = !this.flag;
          })
      }
    }
    .backgroundColor(Color.Transparent)
    .gesture(
      PanGesture(this.panOption)
        .onActionStart((event: GestureEvent) => {})
        .onActionUpdate((event: GestureEvent) => {
          this.windowPosition.x += event.offsetX;
          this.windowPosition.y += event.offsetY;
          let top = CommonConstants.DEFAULT_HEIGHT;
          let bottom = display.getDefaultDisplaySync().height - this.subWindow.getWindowProperties().windowRect.height
            - top;
          if (this.windowPosition.y < top) {
            this.windowPosition.y = top;
          } else if (this.windowPosition.y > bottom) {
            this.windowPosition.y = bottom;
          }
          this.subWindow.moveWindowTo(this.windowPosition.x, this.windowPosition.y);
        })
        .onActionEnd((event: GestureEvent) => {
          if (this.windowPosition.x >= display.getDefaultDisplaySync().width / 2) {
            this.windowPosition.x = display.getDefaultDisplaySync().width -
              this.subWindow.getWindowProperties().windowRect.width;
          } else if (event.offsetX < display.getDefaultDisplaySync().width / 2) {
            this.windowPosition.x = 0;
          }
          let top = CommonConstants.DEFAULT_HEIGHT;
          let bottom = display.getDefaultDisplaySync().height - this.subWindow.getWindowProperties().windowRect.height
            - top;
          if (this.windowPosition.y < top) {
            this.windowPosition.y = top;
          } else if (this.windowPosition.y > bottom) {
            this.windowPosition.y = bottom;
          }
          this.subWindow.moveWindowTo(this.windowPosition.x, this.windowPosition.y);
        })
    )
  }
}

显示

我们使用子窗口设置我们的悬浮球大小和

javascript 复制代码
this.windowStage.createSubWindow('ResizeWindowPage', (err, windowClass) => {
  if (err.code > 0) {
    Logger.error('failed to create subWindow Cause:' + err.message);
    return;
  }
  try {
    windowClass.setUIContent('pages/ResizeWindowPage', () => {
      windowClass.setWindowBackgroundColor('#00000000');
    });
    windowClass.moveWindowTo(CommonConstants.DEFAULT_WINDOW_X, CommonConstants.DEFAULT_WINDOW_Y);
    windowClass.resize(vp2px(CommonConstants.DEFAULT_WINDOW_SIZE), vp2px(CommonConstants.DEFAULT_WINDOW_SIZE));
    windowClass.showWindow();
    windowClass.setWindowLayoutFullScreen(true);
  } catch (err) {
    Logger.error('failed to create subWindow Cause:' + err);
  }
})

隐藏

我们调用 子窗口的 destroyWindow 来隐藏我们的悬浮球即可

javascript 复制代码
if (window.findWindow('ResizeWindowPage').isWindowShowing()) {
  window.findWindow('ResizeWindowPage').destroyWindow();
}
最后总结

华为也是推荐我们使用子窗口来实现悬浮球的的效果,最开始是使用dialog来实现的但是效果不好 ,这种方式不可取,所以我这最后决定使用子窗口来实现。 。今天的文章就讲到这里有兴趣的同学可以继续研究 如果你觉得文章还不错麻烦给我三连 关注点赞和转发 如果了解更多鸿蒙开发的知识 可以关注坚果派公众号 。 谢谢

团队介绍

团队介绍:坚果派由坚果等人创建,团队由12位华为HDE以及若干热爱鸿蒙的开发者和其他领域的三十余位万粉博主运营。专注于分享 HarmonyOS/OpenHarmony,ArkUI-X,元服务,仓颉,团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,目前已开发鸿蒙 原生应用,三方库60+,欢迎进行课程,项目等合作。

相关推荐
zhanshuo4 小时前
构建可扩展的状态系统:基于 ArkTS 的模块化状态管理设计与实现
harmonyos
zhanshuo4 小时前
ArkTS 模块通信全解析:用事件总线实现页面消息联动
harmonyos
codefish7989 小时前
鸿蒙开发学习之路:从入门到实践的全面指南
harmonyos
yrjw15 小时前
一款基于react-native harmonyOS 封装的【文档】文件预览查看开源库(基于Harmony 原生文件预览服务进行封装)
harmonyos
搜狐技术产品小编20231 天前
搜狐新闻直播间适配HarmonyOs实现点赞动画
华为·harmonyos
zhanshuo2 天前
ArkUI 玩转水平滑动视图:超全实战教程与项目应用解析
harmonyos·arkui
zhanshuo2 天前
ArkUI Canvas 实战:快速绘制柱状图图表组件
harmonyos·arkui
zhanshuo2 天前
手把手教你用 ArkUI 写出高性能分页列表:List + onScroll 实战解析
harmonyos
zhanshuo2 天前
深入解析 ArkUI 触摸事件机制:从点击到滑动的开发全流程
harmonyos
i仙银2 天前
鸿蒙沙箱浏览器 - SandboxFinder
app·harmonyos