[经验分享] OpenHarmony应用组件自定义事件分发 原创

深开鸿_张守忠 显示全部楼层 发表于 2024-1-16 19:57:50

简介:

ArkUI在处理触屏事件时,会在触屏事件触发前进行按压点和组件区域的触摸测试,来收集需要响应触屏事件的组件,再基于触摸测试结果分发相应的触屏事件。在父节点,可以通过onChildTouchTest决定如何让子节点去做触摸测试,影响子组件的触摸测试,最终影响后续的触屏事件分发 。

文档环境:

  • 开发环境:Windows 10专业版
  • DevEco Studio版本:DevEco Studio 4.0Release (4.0.0.600)
  • SDK版本:4.1.6.1 (full sdk)
  • API版本:Version 11
  • 开发板型号:DAYU200(RK3568)
  • 系统版本:OpenHarmony 4.1.6.1

演示demo:

  • 新建一个 Stage 框架的 demo 工程,在page/Index.ets中通过stack组件封装大小两个圆形按钮组件,分别用蓝色和黄色的背景色来区分并分别增加OnClick事件,在事件回调函数中调用提示组件,提示OnClick事件已响应。
  • 在stack组件中增加onChildTouchTest属性,在其回调函数中通过 对参数TouchTestInfo进行解析,判断按压点是否在大圆小圆内或者在大圆外,如果在小圆内则向小圆分发事件,如果在大圆内但在小圆外则向小圆分发事件,其他情况不向大圆和小圆分发事件。

demo运行效果:

首页 点击蓝圈 点击黄圈
image image image

核心代码如下:

import ShowToast from 'ShowToast';
import Logger from 'util/Logger';

const TAG: string = 'CustomClickEvent';

@Entry
@Component
struct CustomClickEvent {
  private btnFontColor: Resource = $r('app.color.white');

  isTouchPointInCircle(info: TouchTestInfo): boolean {
    let circleCenterX = info.rect.x + info.rect.width / 2;
    let circleCenterY = info.rect.y + info.rect.height / 2;
    let circleRadius = info.rect.width / 2;
    let distance = Math.sqrt((circleCenterX - info.parentX)**2 + (circleCenterY - info.parentY)**2);
    Logger.info(TAG, `TouchPoinInCircle circleCenterX: ${circleCenterX}, circleCenterY: ${circleCenterY},\
     circleRadius: ${circleRadius}, distance: ${distance}`);
    if (distance <= circleRadius) {
      return true;
    }
    return false;
  }

  build() {
    Column() {
      Column() {
        Column({ space: 12 }) {
          Stack({ alignContent: Alignment.Bottom }) {
            Button({ type: ButtonType.Circle }) {
              Row() {
                Text($r('app.string.custom_click_big_btn'))
                  .fontSize(21)
                  .fontWeight(500)
                  .fontFamily('HarmonyHeiTi-Medium')
                  .textAlign(TextAlign.Center)
                  .id('BigCircle')
                  .padding({ top: 56, bottom: 300 })
              }
              .alignItems(VerticalAlign.Top)
            }
            .backgroundColor('#007DFF')
            .width('100%')
            .height('100%')
            .fontSize(21)
            .fontWeight(500)
            .fontColor(this.btnFontColor)
            .onClick(() => {
              ShowToast.longToast($r('app.string.custom_bigcircle_prompt'));
            })

            Button($r('app.string.custom_click_small_btn'), { type: ButtonType.Circle })
              .backgroundColor('#F7CE00')
              .width(240)
              .fontSize(21)
              .fontWeight(500)
              .borderRadius(20)
              .fontColor(this.btnFontColor)
              .id('SmallCircle')
              .onClick(() => {
                ShowToast.longToast($r('app.string.custom_smallcircle_prompt'));
              })
          }
          .width('100%')
          .hitTestBehavior(HitTestMode.Block)
          .onChildTouchTest((touchinfo) => {
            for(let i = 0; i < touchinfo.length; i++) {
              let info: TouchTestInfo = touchinfo[i];
              if (info.id == 'SmallCircle' && info.x > 0 && info.y > 0 && this.isTouchPointInCircle(info) == true) {
                Logger.info(TAG, `touchinfo touch point at scope of component: ${info.id}`);
                return { id: 'SmallCircle', strategy: TouchTestStrategy.FORWARD };
              }
              if (info.id == 'BigCircle' && info.x > 0 && info.y > 0 && this.isTouchPointInCircle(info) == true) {
                Logger.info(TAG, `touchinfo touch point at scope of component: ${info.id}`);
                return { id: 'BigCircle', strategy: TouchTestStrategy.FORWARD };
              }
            }
            return { strategy: TouchTestStrategy.DEFAULT };
          })
        }
        .padding({ left: 24, right: 24, bottom: 32 })
        Column() {
          Row() {
            Button({ type: ButtonType.Circle })
              .backgroundColor('#007DFF')
              .width(8)
              .height(8)
            Text($r('app.string.big_circle_prompt'))
              .fontSize(14)
              .fontWeight(400)
              .fontFamily('HarmonyHeiTi')
              .textAlign(TextAlign.Start)
              .margin({ left: 8 })
          }
          .alignItems(VerticalAlign.Center)
          .justifyContent(FlexAlign.Center)

          Row() {
            Button({ type: ButtonType.Circle })
              .backgroundColor('#F7CE00')
              .width(8)
              .height(8)
            Text($r('app.string.small_circle_prompt'))
              .fontSize(14)
              .fontWeight(400)
              .fontFamily('HarmonyHeiTi')
              .textAlign(TextAlign.Start)
              .margin({ left: 8 })
          }
          .alignItems(VerticalAlign.Center)
          .justifyContent(FlexAlign.Center)
        }
      }
      .height('90%')
      .width('100%')
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.Center)
      .flexShrink(1)
    }
    .height('100%')
    .width('100%')
    .backgroundColor($r('app.color.background_shallow_grey'))
  }
}
  

sample仓地址:

本功能的sample仓地址:https://gitee.com/openharmony/applications_app_samples/tree/master/code/UI/ArkTsComponentCollection/ComponentCollection

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部