事件传递和手势

278 阅读5分钟

事件传递

  • HitTestMode
  • hitTestBehavior
  • onChildTouchTest
  • onTouchIntercept

手势

名称描述
TapGesture点击手势,支持单次点击、多次点击识别。
LongPressGesture长按手势。
PanGesture平移手势,滑动最小距离为5vp时识别成功。
PinchGesture捏合手势。
RotationGesture旋转手势。
SwipeGesture滑动手势,滑动最小速度为100vp/s时识别成功。
GestureGroup手势识别组,多种手势组合为复合手势,支持连续识别、并行识别和互斥识

GestureEvent对象说明

类型描述
repeatboolean是否为重复触发事件,用于LongPressGesture手势触发场景。
offsetXnumber手势事件偏移量X,单位为vp,用于PanGesture手势触发场景,从左向右滑动offsetX为正,反之为负。
offsetYnumber手势事件偏移量Y,单位为vp,用于PanGesture手势触发场景,从上向下滑动offsetY为正,反之为负。
anglenumber用于RotationGesture手势触发场景时,表示旋转角度。用于SwipeGesture手势触发场景时,表示滑动手势的角度,即两根手指间的线段与水平方向的夹角变化的度数。**说明:**角度计算方式:滑动手势被识别到后,连接两根手指之间的线被识别为起始线条,随着手指的滑动,手指之间的线条会发生旋转,根据起始线条两端点和当前线条两端点的坐标,使用反正切函数分别计算其相对于水平方向的夹角,最后arctan2(cy2-cy1,cx2-cx1)-arctan2(y2-y1,x2-x1)为旋转的角度。以起始线条为坐标系,顺时针旋转为0到180度,逆时针旋转为-180到0度。
scalenumber缩放比例,用于PinchGesture手势触发场景。
pinchCenterXnumber捏合手势中心点的x轴坐标,单位为vp,用于PinchGesture手势触发场景。
pinchCenterYnumber捏合手势中心点的y轴坐标,单位为vp,用于PinchGesture手势触发场景。
speed8+number滑动手势速度,即所有手指相对当前组件元素原始区域滑动的平均速度,单位为vp/秒,用于SwipeGesture手势触发场景。
fingerList8+FingerInfo[]输入源为触屏产生的手势,fingerList中会包含触发事件的所有触点信息;由鼠标发起的手势,fingerList中只会有一条记录;触摸板的事件大类与鼠标一致,所以由触摸板发起的手势,fingerList只会携带一条记录。**说明:**手指索引编号与位置对应,即fingerList[index]的id为index。先按下且未参与当前手势触发的手指在fingerList中对应位置为空。
timestamp8+number事件时间戳。**说明:**单位:ns
target8+EventTarget触发手势事件的元素对象显示区域。
source8+SourceType事件输入设备。
pressure9+number按压的压力大小。
tiltX9+number手写笔在设备平面上的投影与设备平面X轴的夹角。
tiltY9+number手写笔在设备平面上的投影与设备平面Y轴的夹角。
sourceTool9+SourceTool事件输入源。
velocityX10+number用于PanGesture手势中,获取当前手势的x轴方向速度。坐标轴原点为屏幕左上角,分正负方向速度,从左往右为正,反之为负。单位为vp/s。
velocityY10+number用于PanGesture手势中,获取当前手势的y轴方向速度。坐标轴原点为屏幕左上角,分正负方向速度,从上往下为正,反之为负。单位为vp/s。
velocity10+number用于PanGesture手势中,获取当前手势的主方向速度。为xy轴方向速度的平方和的算术平方根。单位为vp/s。

TapGesture

参数

  • count?: number; 表示相比上次300ms再次点击,总共点击了几次才响应这里的事件
  • fingers?: number 几根手指头

属性

  • onAction 触发的回调
  • tag 设置Tap手势标志,用于自定义手势判定时区分绑定的手势。
// 单指双击文本触发手势事件
Text('Click twice').fontSize(28)
  .gesture(
    TapGesture({ count: 2 })
      .onAction((event: GestureEvent) => {
        console.log('点击了两次')
      })
  )
  // 如果设置了 onClick 则不会触发 TapGesture
  .onClick(()=>{
  this.color = Color.Red
})

LongPressGesture 长按

参数

  • duration: 500 长按几秒
  • fingers: 1 几个手指头
  • repeat: false 是否重复,肯定不重复呀

属性

  • onAction 触发的任务
  • onActionEnd 长按动作一结束触发,手指头抬起来的时候
Text('LongPress onAction:' + this.count).fontSize(28)// 单指长按文本触发该手势事件
  .gesture(
    LongPressGesture({
      duration: 500,// 长按几毫秒触发 默认500
      fingers: 1, // 几个手指头,默认1个
      // repeat: true // 是否重复,一半也不会重复
    })// 由于repeat设置为true,长按动作存在时会连续触发,触发间隔为duration(默认值500ms)
      .onAction((event: GestureEvent) => {
        // if (event && event.repeat) {
          this.count++
        // }
      })// 长按动作一结束触发
      .onActionEnd((event: GestureEvent) => {
        this.count = 0
      })
  )

PanGesture 拖拽

offsetX 和 offsetY 每次移动都从新0开始,记得累加哈 参数

  • fingers?: number; 手指个数 默认是1
  • direction?: PanDirection;用于指定设置滑动方向,此枚举值支持逻辑与(&)和逻辑或(|)运算。默认值:PanDirection.All,比如只有水平方向可以,垂直方向可以,left ,right top ,bottom
  • distance?: number;用于指定触发拖动手势事件的最小拖动距离,单位为vp。默认值:5

属性

  • onActionStart
  • onActionUpdate
  • onActionEnd
  • onActionCancel
@State offsetX: number = 0
@State offsetY: number = 0
@State positionX: number = 0
@State positionY: number = 0
// private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Left | PanDirection.Right })
private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All })

build() {
  Column() {
    Column() {
      Text('PanGesture offset:\nX: ' + this.offsetX + '\n' + 'Y: ' + this.offsetY)
    }
    .height(200)
    .width(300)
    .padding(20)
    .border({ width: 3 })
    .margin(50)
    .translate({ x: this.offsetX, y: this.offsetY, z: 0 }) // 以组件左上角为坐标原点进行移动
    // 左右拖动触发该手势事件
    .gesture(
      PanGesture(this.panOption)
        .onActionStart((event: GestureEvent) => {
          console.info('Pan start')
        })
        .onActionUpdate((event: GestureEvent) => {
          if (event) {
            this.offsetX = this.positionX + event.offsetX
            this.offsetY = this.positionY + event.offsetY
          }
        })
        .onActionEnd((event: GestureEvent) => {
          this.positionX = this.offsetX
          this.positionY = this.offsetY
          console.info('Pan end')
        })
        .onActionCancel(() => {
          console.info('Pan onActionCancel')
        })
    )

PinchGesture 用于触发捏合手势,放大,触发捏合手势的最少手指为2指,比如PhotoView的实现

event.scale 每次都是从新1开始,记得累加哈

参数

  • fingers: 2 手指个数,默认是2个
  • distance 距离

属性

  • onActionStart
  • onActionUpdate
  • onActionEnd
  • onActionCancel
@Entry
@Component
struct PinchGestureExample {
  @State scaleValue: number = 1
  @State pinchValue: number = 1
  @State pinchX: number = 0
  @State pinchY: number = 0

  build() {
    Column() {
      Stack() {
        Image($r('app.media.img')).width('100%').height('100%').scale({ x: this.scaleValue, y: this.scaleValue, z: 0 })
        Column() {
          Text('PinchGesture scale:\n' + this.scaleValue)
          Text('PinchGesture center:\n(' + this.pinchX + ',' + this.pinchY + ')')
        }
        .height(200)
        .width(300)
        .padding(20)
        .border({ width: 3 })
        .margin({ top: 100 })
        // 三指捏合触发该手势事件
        .gesture(
          PinchGesture({ fingers: 2 })
            .onActionStart((event: GestureEvent) => {
              console.info('Pinch start')
            })
            .onActionUpdate((event: GestureEvent) => {
              if (event) {
                this.scaleValue = this.pinchValue * event.scale
                this.pinchX = event.pinchCenterX
                this.pinchY = event.pinchCenterY
                console.log("event.scale=>" + event.scale)

              }
            })
            .onActionEnd((event: GestureEvent) => {
              this.pinchValue = this.scaleValue
              console.info('Pinch end')
            })
        )
      }
    }.width('100%')
    .height('100%')
  }
}

RotationGesture

用于触发旋转手势事件,触发旋转手势的最少手指为2指, GestureEvent.angle拿到旋转度数

SwipeGesture 大距离滑动的时候,估计也用不上

GestureGroup

  • mode: GestureMode, GestureMode.Sequence 默认是顺讯识别,只有一个响应 ,Parallel 并发识别 互不影响,Exclusive互斥识别
  • ...gesture: GestureType[] 上面的几个手势

下面是类似photoview,同时识别 移动和缩放

@Entry
@Component
struct PinchGestureExample {
  @State scaleValue: number = 1
  @State pinchValue: number = 1
  @State pinchX: number = 0
  @State pinchY: number = 0
  @State offsetX: number = 0
  @State offsetY: number = 0
  @State positionX: number = 0
  @State positionY: number = 0
  private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All })

  build() {
    Column() {
      Stack() {
        Image($r('app.media.img'))
          .width('100%')
          .interpolation(ImageInterpolation.High)
          .height('100%')
          .scale({ x: this.scaleValue, y: this.scaleValue, z: 0 })
          .translate({ x: this.offsetX, y: this.offsetY })
        Column() {
          Text('PinchGesture scale:\n' + this.scaleValue)
          Text('PinchGesture center:\n(' + this.pinchX + ',' + this.pinchY + ')')
        }
        .height(200)
        .width(300)
        .padding(20)
        .border({ width: 3 })
        .margin({ top: 100 })

        // 三指捏合触发该手势事件

      }.gesture(GestureGroup(GestureMode.Parallel,
        PinchGesture({ fingers: 2 })
          .onActionStart((event: GestureEvent) => {
            console.info('Pinch start')
          })
          .onActionUpdate((event: GestureEvent) => {
            if (event) {
              this.scaleValue = this.pinchValue * event.scale
              this.pinchX = event.pinchCenterX
              this.pinchY = event.pinchCenterY
              console.log("event.scale=>" + event.scale)

            }
          })
          .onActionEnd((event: GestureEvent) => {
            this.pinchValue = this.scaleValue
            console.info('Pinch end')
          }),
        PanGesture(this.panOption)
          .onActionStart((event: GestureEvent) => {
            console.info('Pan start')
          })
          .onActionUpdate((event: GestureEvent) => {
            if (event) {
              this.offsetX = this.positionX + event.offsetX
              this.offsetY = this.positionY + event.offsetY
            }
          })
          .onActionEnd((event: GestureEvent) => {
            this.positionX = this.offsetX
            this.positionY = this.offsetY
            console.info('Pan end')
          })
      ))
    }.width('100%')
    .height('100%')
  }
}