鸿蒙开发中手势事件(单一事件)解析

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、鸿蒙手势体系概览

手势类型触发条件典型应用场景
点击(Click)手指按下并抬起按钮点击、图标选择
长按(LongPress)持续按压超过500ms弹出菜单、拖动准备
拖拽(Pan)按压后移动滑动列表、元素拖动
捏合(Pinch)双指缩放图片放大/缩小
旋转(Rotation)双指旋转图片旋转

二、基础手势使用

1. 点击手势(Click)
@Entry
@Component
struct ClickExample {
  @State count: number = 0;

  build() {
    Column() {
      Text(`点击次数: ${this.count}`)
        .fontSize(20)
        .margin(10)
      
      Button('点我')
        .onClick(() => { // 内置点击事件
          this.count++;
        })
      
      // 使用Gesture单独实现点击
      Text('自定义点击区域')
        .gesture(
          TapGesture()
            .onAction(() => {
              this.count++;
              console.log('Tap触发');
            })
        )
    }
  }
}

参数说明

  • onAction:点击完成时触发(手指抬起)
2. 长按手势(LongPress)
Text('长按触发菜单')
  .gesture(
    LongPressGesture()
      .onActionStart(() => console.log('开始长按')) // 按压时
      .onAction(() => showContextMenu()) // 长按完成
      .onActionEnd(() => console.log('结束')) // 手指抬起
  )

关键属性

  • duration:自定义长按阈值(默认500ms)
    LongPressGesture({ duration: 1000 }) // 改为1秒触发

三、高级手势控制

1. 拖拽手势(Pan)
@Entry
@Component
struct DragExample {
  @State offsetX: number = 0;
  @State offsetY: number = 0;

  build() {
    Stack() {
      Image($r('app.media.icon'))
        .width(100)
        .height(100)
        .offset({ x: this.offsetX, y: this.offsetY })
        .gesture(
          PanGesture()
            .onActionStart(() => console.log('开始拖动'))
            .onActionUpdate((event: GestureEvent) => {
              this.offsetX += event.offsetX;
              this.offsetY += event.offsetY;
            })
            .onActionEnd(() => console.log('拖动结束'))
        )
    }
    .height('100%')
    .width('100%')
  }
}

事件对象

  • event.offsetX/Y:相对于起点的位移
  • event.globalX/Y:全局坐标
2. 捏合缩放(Pinch)
@State scale: number = 1;

Image($r('app.media.photo'))
  .scale({ x: this.scale, y: this.scale })
  .gesture(
    PinchGesture()
      .onActionUpdate((event: GestureEvent) => {
        this.scale *= event.scale; // event.scale为缩放因子
      })
  )

四、手势组合与冲突解决

1. 手势并行处理
Text('多手势支持')
  .gesture(
    GestureGroup(
      GestureMode.Parallel, // 并行模式
      [
        TapGesture().onAction(() => console.log('点击')),
        LongPressGesture().onAction(() => console.log('长按'))
      ]
    )
  )

 2. 手势互斥(优先级控制)

GestureGroup(
  GestureMode.Exclusive, // 互斥模式
  [
    PanGesture().onActionUpdate((e) => { /* 拖拽逻辑 */ }),
    LongPressGesture().onAction(() => console.log('长按优先'))
  ]
)

五、自定义手势开发

1. 监听原始触摸事件
@Entry
@Component
struct TouchExample {
  @State touchX: number = 0;
  @State touchY: number = 0;

  build() {
    Column()
      .onTouch((event: TouchEvent) => {
        if (event.type === TouchType.Down) {
          this.touchX = event.touches[0].x;
          this.touchY = event.touches[0].y;
        }
      })
  }
}

事件类型

  • TouchType.Down:按下
  • TouchType.Move:移动
  • TouchType.Up:抬起
2. 实现双击检测
let lastTapTime: number = 0;

Text('双击区域')
  .gesture(
    TapGesture({ count: 2 }) // 监听双击
      .onAction(() => console.log('双击触发'))
  )

六、性能优化与常见问题

1. 手势拦截优化
Column()
  .gesture(
    PanGesture()
      .onActionUpdate((e) => {
        if (Math.abs(e.offsetX) > 10) {
          // 水平移动超过10vp才触发
          handlePanMove(e);
        }
      })
  )
2. 常见问题解决
问题原因解决方案
手势无响应父组件拦截触摸事件检查父容器的touchable属性
拖拽卡顿频繁触发状态更新使用@Prop代替@State减少渲染
多手势冲突未正确设置GestureGroup模式明确使用ParallelExclusive

七、完整示例:图片查看器

@Entry
@Component
struct ImageViewer {
  @State scale: number = 1;
  @State offsetX: number = 0;
  @State offsetY: number = 0;

  build() {
    Stack() {
      Image($r('app.media.pic'))
        .scale({ x: this.scale, y: this.scale })
        .offset({ x: this.offsetX, y: this.offsetY })
        .gesture(
          GestureGroup(
            GestureMode.Parallel,
            [
              // 双击复位
              TapGesture({ count: 2 })
                .onAction(() => {
                  this.scale = 1;
                  this.offsetX = 0;
                  this.offsetY = 0;
                }),
              
              // 双指缩放
              PinchGesture()
                .onActionUpdate((e) => {
                  this.scale *= e.scale;
                }),
              
              // 单指拖动
              PanGesture()
                .onActionUpdate((e) => {
                  this.offsetX += e.offsetX;
                  this.offsetY += e.offsetY;
                })
            ]
          )
        )
    }
    .width('100%')
    .height('100%')
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值