HarmonyOS 鸿蒙Next:实现一个简单的app内部的悬浮窗

发布于 1周前 作者 yuanlaile 来自 鸿蒙OS

HarmonyOS 鸿蒙Next:实现一个简单的app内部的悬浮窗

简单的能点击能拖动的component  但是长按不能出现拖拽的现象

2 回复

参考demo:

1、onWindowStageCreate中记录windowStage

onWindowStageCreate(windowStage: window.WindowStage): void {
 
    // 记录
    AppStorage.setOrCreate("windowStage",windowStage)
  }

2、FloatWindow页面

//FloatWindow.ets
// 引入window类
import window from '[@ohos](/user/ohos).window';
import { BusinessError } from '[@ohos](/user/ohos).base';
import router from '[@ohos](/user/ohos).router';

[@Entry](/user/Entry)
[@Component](/user/Component)
struct FloatWindow {
  // 定义windowClass变量,用来接收创建的悬浮窗
  // 自定义创建悬浮窗方法
  createFloatWindow() {
    // 窗口类型设置为window.WindowType.TYPE_FLOAT
    let windowStage = AppStorage.get("windowStage") as window.WindowStage;

    // let config:window.Configuration = {name: "floatWindow", windowType: window.WindowType.TYPE_FLOAT, ctx: getContext(this)};
    // 创建悬浮窗
    windowStage.createSubWindow("floatWindow", (err, win) => {

      if (err.code) {
        console.error('Failed to create the floatWindow. Cause: ' + JSON.stringify(err));
        return;
      }
      console.info('Succeeded in creating the floatWindow. Data: ' + JSON.stringify(win));

      // 设置悬浮窗位置
      win.moveWindowTo(300, 300, (err) => {
        if (err.code) {
          console.error('Failed to move the window. Cause:' + JSON.stringify(err));
          return;
        }
        console.info('Succeeded in moving the window.');
      });
      // 设置悬浮窗大小
      win.resize(500, 500, (err) => {
        if (err.code) {
          console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
          return;
        }
        console.info('Succeeded in changing the window size.');
      });
      // 为悬浮窗加载页面内容,这里可以设置在main_pages.json中配置的页面
      win.setUIContent("pages/FloatContent", (err: BusinessError) => {
        if (err.code) {
          console.error('Failed to load the content. Cause:' + JSON.stringify(err));
          return;
        }
        win.setWindowBackgroundColor("#00000000")
        console.info('Succeeded in loading the content.');
        // 显示悬浮窗。
        win.showWindow((err: BusinessError) => {
          if (err.code) {
            console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
            return;
          }
          console.info('Succeeded in showing the window.');
        });
      });

    });
  }

  // 自定义销毁悬浮窗方法
  destroyFloatWindow() {
    // 用windowClass调用destroyWindow销毁悬浮窗
    window.findWindow("floatWindow").destroyWindow((err) => {
      if (err.code) {
        console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
        return;
      }
      console.info('Succeeded in destroying the window.');
    });
  }

  build() {
    Row() {
      Column() {
        TextInput()
        Button('创建悬浮窗')
          .backgroundColor('#F9C449')
          .onClick(() => {
            // 点击按钮调用创建悬浮窗方法
            this.createFloatWindow();
          })
        Button('销毁悬浮窗')
          .margin({ top: 20 })
          .backgroundColor('#F9C449')
          .onClick(() => {
            // 点击按钮调用销毁悬浮窗方法
            this.destroyFloatWindow();
          })

        Button('跳转下一页')
          .margin({ top: 20 })
          .backgroundColor('#F9C449')
          .onClick(() => {
            // 点击按钮调用销毁悬浮窗方法
            router.pushUrl({
              url: 'pages/Index'
            })
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

3、FloatContent页面

//FloatContent.ets
import window from '[@ohos](/user/ohos).window';

interface Position {
  x: number,
  y: number
}
[@Entry](/user/Entry)
[@Component](/user/Component)
struct FloatContent {
  [@State](/user/State) message: string = 'float window'
  private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All });
  // 创建位置变量,并使用[@Watch](/user/Watch)监听,变量发生变化调用moveWindow方法移动窗口
  [@State](/user/State) [@Watch](/user/Watch)("moveWindow") windowPosition: Position = { x: 0, y: 0 };
  floatWindow: window.Window = window.findWindow("floatWindow")
  // 通过悬浮窗名称“floatWindow”获取到创建的悬浮窗
  aboutToAppear() {
    this.floatWindow = window.findWindow("floatWindow")
    this.floatWindow.setPreferredOrientation(window.Orientation.LANDSCAPE)
  }
  // 将悬浮窗移动到指定位置
  moveWindow() {
    this.floatWindow.moveWindowTo(this.windowPosition.x, this.windowPosition.y);
  }

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(30)
          .fontColor(Color.White)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .borderRadius(500)
    .height('100%')
    .gesture(
      // 绑定PanGesture事件,监听拖拽动作
      PanGesture(this.panOption)
        .onActionStart((event: GestureEvent) => {
          console.info('Pan start');
        })
          // 发生拖拽时,获取到触摸点的位置,并将位置信息传递给windowPosition
        .onActionUpdate((event: GestureEvent) => {
          this.windowPosition.x += event.offsetX;
          this.windowPosition.y += event.offsetY;
        })
        .onActionEnd(() => {
          console.info('Pan end');
        })
    )
    .border({
      style: BorderStyle.Dotted
    })
    .backgroundColor("#E8A49C")
  }
}

在HarmonyOS(鸿蒙)系统中实现一个简单的App内部悬浮窗功能,可以通过使用悬浮窗服务(FloatingWindowService)来完成。以下是一个简要的实现步骤概述:

  1. 权限声明:首先,在config.json文件中声明悬浮窗权限,确保应用有权限创建悬浮窗。

  2. 创建悬浮窗布局:在resources/layout目录下创建一个XML布局文件,定义悬浮窗的UI。

  3. 启动悬浮窗服务:在App的适当位置(如某个Activity中),通过AbilityContext启动悬浮窗服务。使用Intent指定悬浮窗的布局和必要的参数。

  4. 处理悬浮窗逻辑:在悬浮窗服务的代码中,处理悬浮窗的显示、隐藏、移动等逻辑。可以通过WindowManager来管理悬浮窗的视图。

  5. 与主App交互:如果需要,可以通过广播、AIDL等方式实现悬浮窗与主App之间的数据交互。

请注意,实现细节可能因HarmonyOS版本和具体需求而有所不同。确保遵循最新的HarmonyOS开发文档和最佳实践。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部