鸿蒙开发中 Gesture(手势)用法

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

一、手势系统核心概念

1. 手势类型与触发条件
手势类型触发条件典型应用场景
Tap(点击)快速按下并释放(<300ms)按钮点击、选择操作
LongPress(长按)持续按压(≥500ms)上下文菜单、拖拽准备
Pan(平移)按压后移动(≥5vp)拖拽、滑动操作
Pinch(缩放)双指捏合/扩张图片缩放、地图缩放
Rotation(旋转)双指旋转图片旋转、3D模型控制
Swipe(快速滑动)快速单向移动(速度>100vp/s)翻页、删除操作
2. 手势识别流程

    A[触摸事件] --> B(命中测试)
    B --> C{是否在目标区域}
    C -->|是| D[手势识别器分析]
    C -->|否| E[事件丢弃]
    D --> F[触发回调]

二、基础使用与API详解

1. 单手势绑定(声明式API)
@Entry
@Component
struct GestureExample {
  @State scale: number = 1.0;
  @State angle: number = 0;

  build() {
    Column() {
      Image($r('app.media.logo'))
        .scale({ x: this.scale, y: this.scale })
        .rotate({ angle: this.angle })
        // 绑定缩放手势
        .gesture(
          Gesture(GestureType.Pinch)
            .onActionUpdate((event: GestureEvent) => {
              this.scale *= event.scale; // event.scale为缩放比例
            })
        )
        // 绑定旋转手势
        .gesture(
          Gesture(GestureType.Rotation)
            .onActionUpdate((event: GestureEvent) => {
              this.angle += event.angle; // event.angle为旋转弧度
            })
        )
    }
  }
}

2. 多手势组合(GestureGroup)

import { Gesture, GestureGroup } from '@ohos.gesture';

private complexGesture = new GestureGroup({
  gestures: [
    new Gesture(GestureType.Pan)
      .onActionStart(() => console.log('拖拽开始'))
      .onActionUpdate((event) => {
        console.log(`位移: X=${event.offsetX}, Y=${event.offsetY}`);
      }),
    new Gesture(GestureType.LongPress)
      .onActionEnd(() => console.log('长按触发'))
  ],
  priority: GesturePriority.Parallel // 并行识别
});

// 绑定到组件
Image($r('app.media.map'))
  .gesture(this.complexGesture)

优先级模式

  • Parallel:并行处理(默认)
  • Exclusive:互斥(高优先级手势优先)
  • Sequence:序列(按添加顺序触发)

三、高级功能实战

1. 自定义手势识别(原始事件处理)
@State startTime: number = 0;
@State startPoint: {x: number, y: number} = {x: 0, y: 0};

build() {
  Column()
    .onTouch((event: TouchEvent) => {
      switch (event.type) {
        case TouchType.Down:
          this.startTime = Date.now();
          this.startPoint = {x: event.touches[0].x, y: event.touches[0].y};
          break;
        case TouchType.Up:
          const duration = Date.now() - this.startTime;
          const distance = Math.sqrt(
            Math.pow(event.touches[0].x - this.startPoint.x, 2) +
            Math.pow(event.touches[0].y - this.startPoint.y, 2)
          );
          
          // 自定义双击识别(间隔<300ms且位移<5vp)
          if (duration < 300 && distance < 5) {
            console.log('双击触发');
          }
          break;
      }
    })
}

2. 手势冲突解决(Exclusive组合)

private swipeAndTap = new GestureGroup({
  gestures: [
    new Gesture(GestureType.Swipe) // 高优先级
      .onActionEnd(() => console.log('滑动生效')),
    new Gesture(GestureType.Tap) // 低优先级
      .onActionEnd(() => console.log('点击生效'))
  ],
  priority: GesturePriority.Exclusive
});

// 绑定到可滑动列表项
ListItem()
  .gesture(this.swipeAndTap)

3. 手势动画(弹性效果)

import curve from '@ohos.curves';

@State offsetX: number = 0;

private panGesture = new Gesture(GestureType.Pan)
  .onActionUpdate((event: GestureEvent) => {
    this.offsetX = event.offsetX;
  })
  .onActionEnd(() => {
    // 使用弹性曲线回弹
    animateTo({
      duration: 500,
      curve: curve.springMotion()
    }, () => {
      this.offsetX = 0;
    })
  });

// 应用动画
Image($r('app.media.card'))
  .translate({ x: this.offsetX })
  .gesture(this.panGesture)

四、调试与性能优化

1. 性能优化建议

场景优化措施
高频手势(如绘图)使用@ohos.worker分线程处理数据
复杂手势树减少嵌套GestureGroup层级
内存管理aboutToDisappear中取消监听
2. 常见问题解决
问题解决方案
手势未触发检查组件尺寸/是否被其他手势拦截
动画卡顿使用硬件加速(hardwareAccelerated
多指手势识别错误通过event.fingerId区分触点

五、案例:图片查看器

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

  private gestureGroup = new GestureGroup({
    gestures: [
      new Gesture(GestureType.Pinch)
        .onActionUpdate((event) => {
          this.scale *= event.scale;
        }),
      new Gesture(GestureType.Pan)
        .onActionUpdate((event) => {
          this.offsetX += event.offsetX;
          this.offsetY += event.offsetY;
        }),
      new Gesture(GestureType.DoubleTap)
        .onActionEnd(() => {
          animateTo({ duration: 200 }, () => {
            this.scale = this.scale === 1.0 ? 2.0 : 1.0;
          })
        })
    ]
  });

  build() {
    Stack() {
      Image($r('app.media.photo'))
        .scale({ x: this.scale, y: this.scale })
        .translate({ x: this.offsetX, y: this.offsetY })
        .gesture(this.gestureGroup)

      // 复位按钮
      Button('重置')
        .onClick(() => {
          animateTo({ duration: 300 }, () => {
            this.scale = 1.0;
            this.offsetX = 0;
            this.offsetY = 0;
          })
        })
    }
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值