HarmonyOS 鸿蒙Next 悬浮窗拖动与悬浮窗内的Web组件事件冲突如何解决 鸿蒙场景化案例

发布于 1周前 作者 zlyuanteng 最后一次编辑是 5天前 来自 鸿蒙OS

【问题现象】

加载HarmonyOS文档的悬浮窗可以拖动,但是不能点击Web组件里的按钮。

下文将以Row组件和Web组件嵌套举例:给Row组件添加自定义拖动手势,Web组件不添加自定义手势,但是有触摸事件

**预期效果:**既可以拖动Row组件,又能点击Web组件中的按钮。

**实际效果:**可以拖动窗口,但是点击Web组件中的按钮没反应。

点击放大

问题代码如下:

build() {
    Row() {
        // 定义Web
        Web({ src: 'https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-web-V5',
          controller: this.controller
        })
          .onPageEnd(()=>{
            this.controller.setScrollable(false)
          })
          .width(CommonConstants.DEFAULT_WINDOW_SIZE1).height(CommonConstants.DEFAULT_WINDOW_SIZE1)
    }
    .backgroundColor(Color.Transparent)

     // 自身响应触摸测试
    .hitTestBehavior(HitTestMode.Block)

     // 移动手势
    .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);
        }),
    )
 }

【背景知识】

在HarmonyOS开发中,触摸事件(onTouch事件)是用户与设备交互的基础,也是所有手势事件组成的基础,手势均由触摸事件组成。当组件被父布局(Stack、Row等任何容器组件)封装住时,对于父、子组件设置的响应手势极容易发生冲突。

【定位思路】

当前手势绑定在了Row组件上,而Web组件位于Row组件的内部,整体结构如下图所示:

点击放大

不难看出是最外层组件,B是A的子组件,两个组件叠加在一起,很容易出现手势冲突问题。

因此需排查以下几点内容:

**(**1)父组件手势优先级高于子组件

父组件具有自定义手势,方法为gesture,子组件未设置自定义手势,但是具有系统级的触摸事件。从手势优先级上来说,一定是子组件高于父组件,正常响应情况应该为:Web组件能响应触控事件,而Row组件失去了拖动响应。而非错误现象表现出的仅有父组件有触控响应,因此不是优先级设置问题。

(2**)阻塞触摸事件**

根据问题代码可知,Row组件为了提高自己的优先级绑定了方法hitTestBehavior(HitTestMode.Block),该方法会阻塞子节点进行触摸测试,因此内层Web组件不会响应onTouch事件。

【解决方案】

根据上述思路,方法hitTestBehavior(HitTestMode.Block)会使子组件的onTouch事件被阻塞,因此不能使用该方法。

代码示例如下:

Row() {
  Web({
    ...
  })
    ...
}
// .hitTestBehavior(HitTestMode.Transparent)
.gesture(
  ...
)

GestureMask.IgnoreInternal则会屏蔽子组件的手势,而非触碰事件。如子组件为List组件时,内置的滑动手势同样会被屏蔽。 若父子组件区域存在部分重叠,则只会屏蔽父子组件重叠的部分。

因此当前场景下应该使用GestureMask.IgnoreInternal方法。

代码示例如下:

.gesture(  PanGesture(this.panOption)  // ...  GestureMask.IgnoreInternal)

处理效果:

点击放大

【总结】

在复杂的应用界面中,多个组件嵌套时同时绑定手势事件,或者同一个组件同时绑定多个手势,都有可能导致手势事件产生冲突,达不到用户的预期效果,因此要分析好事件响应链,排布好手势响应的优先级。

手势分为系统手势自定义手势两类,一般情况下,除非显式声明允许多个手势同时成功,否则同一时间只会有一个手势响应。

常见的手势冲突问题还有:滚动容器嵌套滚动容器事件冲突系统手势和自定义手势之间冲突使用组合手势同时绑定多个同类型手势冲突等等。

下面将举例和Web相关的另一个常见冲突问题:List**、Scroller等滚动容器嵌套Web组件导致滑动事件冲突**。

解决方案:

使用nestedScroll属性设置Web组件的嵌套滚动方式,NestedScrollMode设置成SELF_FIRST时,Web组件滚动到页面边缘后,父组件继续滚动。NestedScrollMode设置为PARENT_FIRST时,父组件先滚动,滚动至边缘后通知Web组件继续滚动。

Web(...)
.nestedScroll({
  scrollForward: NestedScrollMode.PARENT_FIRST,
  scrollBackward: NestedScrollMode.SELF_FIRST
})

Web组件嵌套滚动:Web组件嵌套滚动的典型应用场景为,在一个页面中,有多个独立的区域需要进行滚动,当用户滚动Web区域内容时,可带动其他滚动区域进行滚动,以达到上下滑动页面的用户体验。

更多常见手势冲突问题请见链接内容。

1 回复

作为IT专家,针对HarmonyOS鸿蒙Next悬浮窗拖动与悬浮窗内的Web组件事件冲突的问题,以下是一些可能的解决方案:

  1. 事件拦截与传递

    • 悬浮窗拖动事件和Web组件事件冲突,可能是因为两者都响应了相同的触摸事件。可以尝试在悬浮窗拖动逻辑中拦截触摸事件,避免其传递到Web组件。
    • 或者,通过条件判断,确保在拖动悬浮窗时,不处理Web组件的触摸事件。
  2. 组件属性配置

    • 检查Web组件的draggable属性,确保其不会被意外触发。
    • 在悬浮窗的触摸事件处理中,动态调整Web组件的draggable属性,避免冲突。
  3. 嵌套滚动与滑动

    • 如果悬浮窗内的Web组件包含滚动内容,确保滚动事件不会干扰悬浮窗的拖动。
    • 可以使用nestedScroll属性,设置Web组件的滚动行为,使其与悬浮窗的拖动行为协调。
  4. 性能优化

    • 确保悬浮窗和Web组件的渲染性能良好,避免因性能问题导致的触摸事件响应延迟或冲突。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。希望这些解决方案能帮助你解决HarmonyOS鸿蒙Next悬浮窗拖动与悬浮窗内的Web组件事件冲突的问题。

回到顶部