HarmonyOS 鸿蒙Next如何实现 app 内置全局悬浮球功能?

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

HarmonyOS 鸿蒙Next如何实现 app 内置全局悬浮球功能?

app 内有在主 window 上面的悬浮球, 支持手指按住移动位置, 点击会弹出功能菜单。 不需要退到后台还显示,仅仅在 app 内展示,类似与快捷功能入口

尝试方案:

1. 使用全屏透明子 window ,上面只有悬浮球控件, 但是下层主 window 所有事件不会触发。如关闭子 window 交互事件, 下层 window 事件可以触发, 但是悬浮球又拖动不了

2. 尝试过单页面创建悬浮球, 但是每个页面都要创建一个, 内存消耗较大

3 回复

窗管级悬浮窗请参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-window-0000001820880785#ZH-CN_TOPIC_0000001820880785__windowtype7

参考如下Demo

import { window } from '@kit.ArkUI'; 

@Entry @Component struct Page3 { @State message: string = ‘Hello World’;

build() { Row() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => {

        <span class="hljs-keyword"><span class="hljs-keyword">let</span></span> windowStage = AppStorage.<span class="hljs-keyword"><span class="hljs-keyword">get</span></span>(<span class="hljs-string"><span class="hljs-string">"windowStage"</span></span>) <span class="hljs-keyword"><span class="hljs-keyword">as</span></span> window.WindowStage; 
        windowStage.createSubWindow(<span class="hljs-string"><span class="hljs-string">"test"</span></span>, (err, win) =&gt; { 
          win.setUIContent(<span class="hljs-string"><span class="hljs-string">"pages/Page2"</span></span>); 
          win.resize(<span class="hljs-number"><span class="hljs-number">500</span></span>, <span class="hljs-number"><span class="hljs-number">500</span></span>); 
          win.moveWindowTo(<span class="hljs-number"><span class="hljs-number">200</span></span>, <span class="hljs-number"><span class="hljs-number">200</span></span>); 
          win.showWindow(); 
        }) 
      }) 
  } 
  .width(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) 
} 
.height(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) 
.backgroundColor(Color.Pink) 

} } //FloatContent.ets import window from ‘@ohos.window’;

interface Position { x: number, y: number } @Entry @Component struct FloatContent { @State message: string = ‘float window’ private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All }); // 创建位置变量,并使用@Watch监听,变量发生变化调用moveWindow方法移动窗口 @State @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") } } //FloatWindow.ets // 引入window类 import window from ‘@ohos.window’; import { BusinessError } from ‘@ohos.base’; import router from ‘@ohos.router’;

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

<span class="hljs-comment"><span class="hljs-comment">// let config:window.Configuration = {name: "floatWindow", windowType: window.WindowType.TYPE_FLOAT, ctx: getContext(this)}; </span></span>
<span class="hljs-comment"><span class="hljs-comment">// 创建悬浮窗 </span></span>
windowStage.createSubWindow(<span class="hljs-string"><span class="hljs-string">"floatWindow"</span></span>, (err, win) =&gt; { 

  <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (err.code) { 
    console.error(<span class="hljs-string"><span class="hljs-string">'Failed to create the floatWindow. Cause: '</span></span> + JSON.stringify(err)); 
    <span class="hljs-keyword"><span class="hljs-keyword">return</span></span>; 
  } 
  console.info(<span class="hljs-string"><span class="hljs-string">'Succeeded in creating the floatWindow. Data: '</span></span> + JSON.stringify(win)); 

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

}); 

} // 自定义销毁悬浮窗方法 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(<span class="hljs-string"><span class="hljs-string">'跳转下一页'</span></span>) 
      .margin({ top: <span class="hljs-number"><span class="hljs-number">20</span></span> }) 
      .backgroundColor(<span class="hljs-string"><span class="hljs-string">'#F9C449'</span></span>) 
      .onClick(() =&gt; { 
        <span class="hljs-comment"><span class="hljs-comment">// 点击按钮调用销毁悬浮窗方法 </span></span>
        router.pushUrl({ 
          url: <span class="hljs-string"><span class="hljs-string">'pages/Index'</span></span> 
        }) 
      }) 
  } 
  .width(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) 
} 
.height(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) 

} }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

HarmonyOS 鸿蒙Next实现app内置全局悬浮球功能,可通过子窗口(SubWindow)技术实现。创建悬浮球时,需确保悬浮球控件在顶层窗口显示,且不阻碍下层窗口的事件处理。可使用windowStage.createSubWindow方法创建悬浮球窗口,并设置其位置、大小及内容。确保悬浮球可在全局范围内拖动,并处理其点击事件以弹出功能菜单。如果问题依旧没法解决请加我微信,我的微信是itying888。

回到顶部