HarmonyOS鸿蒙Next中"兄弟"组件如何做到事件透传?

HarmonyOS鸿蒙Next中"兄弟"组件如何做到事件透传? 代码如下,想实现,点击两个按钮的公共区域,同时输出对应的两个日志,如何实现?

.hitTestBehavior(HitTestMode.Transparent)无效

@Entry
@Component
struct HitTestBehaviorExample {
  build() {
    Stack() {
      Stack() {
        Button('inner button')
          .width(50)
          .height(200)
          .hitTestBehavior(HitTestMode.Transparent)
          .onClick(() => {
            console.debug('ztq',`兄弟`)
          })

        Button('inner button')
          .width(200)
          .height(50)
          .backgroundColor('#ff5500')
          .hitTestBehavior(HitTestMode.Transparent)
          .onClick(() => {
            console.debug('ztq',`我在`)
          })
      }
      .width("100%")
      .height("100%")
    }.width(300).height(300).backgroundColor('#F5F5F5')
  }
}

更多关于HarmonyOS鸿蒙Next中"兄弟"组件如何做到事件透传?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

8 回复

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-interaction-basic-principles#%E4%BA%8B%E4%BB%B6%E4%BA%A4%E4%BA%92%E6%B5%81%E7%A8%8B

手势竞争之后只会有一个识别器胜出,而parallelGesture(并行手势绑定方法)只能在父子组件中起作用。

下边是我的蠢办法

@Entry
@Component
export struct ComponentTestPage {
  checkIsInRect(rectOrg: Offset, rectSize: Size, pointOffset: Offset): boolean {
    if (rectOrg.x < pointOffset.x && pointOffset.x < rectOrg.x + rectSize.width
      && rectOrg.y < pointOffset.y && pointOffset.y < rectOrg.y + rectSize.height) {
      return true
    }
    return false
  }

  build() {
    Stack() {
      Text('回应 button')
        .width(200)
        .height(200)
        .backgroundColor('#857')
        .onTouch((e) => {
          if (e.type === TouchType.Up) {
            let comp1Info = this.getUIContext().getComponentUtils().getRectangleById('hy')
            let comp1Offset = comp1Info.windowOffset
            let comp1Size = comp1Info.size
            // hilog.info(0, '[wdk]', `comp1Offset: ${JSON.stringify(comp1Offset)}`)

            let comp2Info = this.getUIContext().getComponentUtils().getRectangleById('hj')
            let comp2Offset = comp2Info.windowOffset
            let comp2Size = comp2Info.size
            // hilog.info(0, '[wdk]', `comp2Offset: ${JSON.stringify(comp2Offset)}`)

            let hitOffsetX = this.getUIContext().vp2px(e.touches[0]?.displayX ?? 0)
            let hitOffsetY = this.getUIContext().vp2px(e.touches[0]?.displayY ?? 0)
            let hitOffset: Offset = {
              x: hitOffsetX,
              y: hitOffsetY
            }

            if (this.checkIsInRect(comp1Offset, comp1Size, hitOffset)
              && this.checkIsInRect(comp2Offset, comp2Size, hitOffset)) {
              hilog.info(0, '[wdk]', `11: ${JSON.stringify(11)}`)
            }
          }
        })
        .id('hy')

      Text('呼叫 button')
        .width(200)
        .height(200)
        .backgroundColor('#ff5500')
        .hitTestBehavior(HitTestMode.Transparent)
        .onTouch((e) => {
          if (e.type === TouchType.Up) {
            let comp1Info = this.getUIContext().getComponentUtils().getRectangleById('hy')
            let comp1Offset = comp1Info.windowOffset
            let comp1Size = comp1Info.size
            // hilog.info(0, '[wdk]', `comp1Offset: ${JSON.stringify(comp1Offset)}`)

            let comp2Info = this.getUIContext().getComponentUtils().getRectangleById('hj')
            let comp2Offset = comp2Info.windowOffset
            let comp2Size = comp2Info.size
            // hilog.info(0, '[wdk]', `comp2Offset: ${JSON.stringify(comp2Offset)}`)

            let hitOffsetX = this.getUIContext().vp2px(e.touches[0]?.displayX ?? 0)
            let hitOffsetY = this.getUIContext().vp2px(e.touches[0]?.displayY ?? 0)
            let hitOffset: Offset = {
              x: hitOffsetX,
              y: hitOffsetY
            }

            if (this.checkIsInRect(comp1Offset, comp1Size, hitOffset)
              && this.checkIsInRect(comp2Offset, comp2Size, hitOffset)) {
              hilog.info(0, '[wdk]', `22: ${JSON.stringify(22)}`)
            }
          }
        })
        .id('hj')
        .margin({
          left: 150,
          top: 100
        })
    }
    .width(300)
    .height(300)
    .backgroundColor('#F5F5F5')
  }
}

更多关于HarmonyOS鸿蒙Next中"兄弟"组件如何做到事件透传?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这办法太神了,谢谢老哥!等我研究一下!这确实可行!

HarmonyOS的分布式文件系统让我在多设备间共享文件变得更加方便。

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

讲道理,为啥不好使呢!!!是按照文档来的呀~

@Entry
@Component
struct HitTestBehaviorExample {
  build() {
    Stack() {
        Button('回应 button')
          .width(200)
          .height(200)
          .backgroundColor('#857')
          .onClick(() => {
            console.debug('ztq',`我在`)
          })

        Column(){
          Button('呼叫 button')
            .width(200)
            .height(200)
            .backgroundColor('#ff5500')
            .onClick(() => {
              console.debug('ztq',`兄弟`)
            })
        }.width(200)
        .height(200)
        .hitTestBehavior(HitTestMode.Transparent)
    }.width(300).height(300).backgroundColor('#F5F5F5')
  }
}

在HarmonyOS鸿蒙Next中,兄弟组件事件透传可通过@Provide@Consume装饰器实现。@Provide在父组件定义共享状态,@Consume在子组件接收状态变更。状态变化时自动同步更新,无需显式传递事件。也可使用EventHub进行组件间通信,通过发布订阅模式传递事件和数据。

在HarmonyOS Next中,兄弟组件的事件透传可以通过hitTestBehavior结合事件冒泡机制实现,但需要注意以下几点:

  1. HitTestMode.Transparent仅允许事件穿透到下层组件,但兄弟组件之间是平级关系,无法直接通过此属性实现事件同时触发。

  2. 建议的解决方案:

    • 将两个按钮的公共点击区域提取为一个父组件(例如使用ColumnRow包裹)
    • 在父组件上设置hitTestBehavior(HitTestMode.Transparent)并添加onClick事件
    • 通过事件冒泡,父组件和子按钮可以同时响应点击事件

示例代码调整:

Stack() {
  Column() {
    Button('inner button')
      .onClick(() => { console.debug('按钮1') })
    
    Button('inner button') 
      .onClick(() => { console.debug('按钮2') })
  }
  .onClick(() => { console.debug('公共区域') })
  .hitTestBehavior(HitTestMode.Transparent)
}

这样点击公共区域时会同时触发父组件和对应按钮的事件处理函数。

回到顶部