鸿蒙Next手势详解系列:滑动手势 原创

auhgnixgnahz
发布于 2025-10-15 09:31
浏览
0收藏

鸿蒙ArkTS组件为我们提供了6种基础手势,分别是点击手势(TapGesture)、长按手势(LongPressGesture)、滑动手势(PanGesture)、捏合手势(PinchGesture)、旋转手势(RotationGesture)、快滑手势(SwipeGesture)。
这些手势的回调函数的事件信息都封装在GestureEvent对象中,本文主要介绍滑动手势,因此也只介绍滑动手势回调可接收到的GestureEvent属性。
GestureEvent对象在PanGesture中的回调属性:

名称 说明
offsetX 相对于手指按下时的偏移量X,单位为vp
offsetY 相对于手指按下时的偏移量Y,单位为vp
fingerList FingerInfo[],包含触发事件的所有触点信息
velocityX 手势的x轴方向速度,单位为vp/s
velocityY 手势的y轴方向速度
velocity 手势的主方向速度

FingerInfo手指信息说明:

名称 说明
id 手指的索引编号
globalX 相对于应用窗口左上角的x轴坐标,单位为vp
globalY 相对于应用窗口左上角的y轴坐标
localX 相对于当前组件元素原始区域左上角的x轴坐标,单位为vp
localY 相对于当前组件元素原始区域左上角的y轴坐标
displayX 相对于屏幕左上角的x轴坐标,单位为vp
displayY 相对于屏幕左上角的y轴坐标
hand 表示事件是由左手点击还是右手点击触发

注意

1.分清楚offset、global、local、display这些坐标相对位置!!!
2.当滑动组件在应用窗口时global和display是一样的。当滑动组件在子窗口时,是不一样的。
3.当滑动组件上层有其他组件遮挡时,会拦截滑动事件,这时需要给上层组件设置组件的触摸测试类型hitTestBehavior,None不响应手势。

接下来看一下滑动手势PanGesture的手势参数回调事件

名称 说明
fingers 指定触发滑动的最少手指数
direction 指定触发滑动的手势方向
distance 指定触发滑动手势事件的最小滑动距离
onActionStart 滑动手势识别成功回调
onActionUpdate 滑动手势更新回调
onActionEnd 滑动手势结束回调
onActionCancel 滑动手势取消回调

手势方向PanDirectionAll(所有方向)、Horizontal(水平方向)、Vertical(竖直方向)、Left(向左滑动)、Right(向右滑动)、Up(向上滑动)、Down(向下滑动)、None(任何方向都不可触发滑动)8个值,支持逻辑与(&)和逻辑或(|)运算。

接下来,通过一个简单的滑动演示,直观看一下以上的参数变化:

鸿蒙Next手势详解系列:滑动手势-鸿蒙开发者社区
观察可发现:当单指滑动时
1.每次触发滑动回调之后,X,Y偏移量会重新计算,并且是本次滑动的总距离
2.滑动过程中(localX-offsetX)和(localY-offsetY)的值是不变的,也就是手指点击的位置相对于滑动组件左上角的x,y的偏移量
3.global、display的坐标只和手指的滑动位置有关

看一下设置成双指触发时的滑动回调参数:
鸿蒙Next手势详解系列:滑动手势-鸿蒙开发者社区
观察上图左右手指1、2的坐标变化:
可发现左图手指1在右,手指2在左,右图手指1在左,手指2在右
这是因为手指是按照手指触摸屏幕顺序记录的。先触摸到屏幕的手指为手指1。

通过以上对滑动事件回调函数的了解,我们就可以利用这些回调参数实现我们想要的滑动效果了。

测试代码

import { showToast } from '../utils/ToastUtil'

@Entry
@ComponentV2
struct PanGestureTest {
  @Local startOffsetX:number=0
  @Local startOffsetY:number=0
  @Local currentOffsetX:number=0
  @Local currentOffsetY:number=0
  @Local panFingers: number = 1
  @Local panDirection: PanDirection = PanDirection.All
  //GestureEvent 回调信息
  @Local offsetX: number = 0 //相对于手指按下时的偏移量X,vp
  @Local offsetY: number = 0 //对于手指按下时的偏移量Y,vp
  @Local fingerList: FingerInfo[] = [] // 触屏手指触发事件的所有触点信息
  @Local velocityX: number = 0 //手势的x轴方向速度 , vp/s 正负同坐标轴方向
  @Local velocityY: number = 0 //手势的y轴方向速度
  @Local velocity: number = 0 //手势的主方向速度

  build() {
    Column({space:20}) {
      Row().backgroundColor(Color.Red).width(300).height(100)
        .offset({x:this.currentOffsetX,y:this.currentOffsetY})
        .gesture(
          PanGesture({ fingers: this.panFingers, direction: this.panDirection })
            //滑动手势识别成功回调
            .onActionStart((event: GestureEvent) => {
               showToast('手势开始')
            })
              //滑动手势更新回调
            .onActionUpdate((event: GestureEvent) => {
              this.offsetX = event.offsetX
              this.offsetY=event.offsetY
              this.fingerList=event.fingerList
              this.velocityX=event.velocityX
              this.velocityY=event.velocityY
              this.velocity=event.velocity
              //计算滑动偏移量
              this.currentOffsetX = this.startOffsetX + this.offsetX
              this.currentOffsetY = this.startOffsetY + this.offsetY
            })
              //滑动手势结束回调
            .onActionEnd((event: GestureEvent) => {
                this.startOffsetX = this.currentOffsetX
                this.startOffsetY = this.currentOffsetY
            })
              //滑动手势取消回调
            .onActionCancel(() => {

            })
        )
      Row() {
        Text("触发手指数")
        Counter() {
          Text(this.panFingers.toString())
        }
        .onInc(() => {
          if (this.panFingers<3) {
            this.panFingers++;
          }
        })
        .onDec(() => {
          if (this.panFingers > 1) {
            this.panFingers--;
          }
        })
      }
      Column({space:10}){
        Text('X偏移量      '+this.offsetX)
        Text('Y偏移量      '+this.offsetY)
        Text('X轴方向速度   '+this.velocityX)
        Text('Y轴方向速度   '+this.velocityY)
        Text('主方向速度    '+this.velocity)
        Text('触发手指数量 '+this.fingerList.length)
        List(){
          ForEach(this.fingerList,(item:FingerInfo,index:number)=>{
            ListItem(){
              Column({space:5}){
                Text('手指'+(index+1))
                Text('相对于应用窗口左上角的x轴坐标'+item.globalX)
                Text('相对于应用窗口左上角的y轴坐标'+item.globalY)
                Text('相对于当前组件元素原始区域左上角的x轴坐标'+item.localX)
                Text('相对于当前组件元素原始区域左上角的y轴坐标'+item.localY)
                Text('相对于屏幕左上角的x轴坐标'+item.displayX)
                Text('相对于屏幕左上角的y轴坐标'+item.displayY)
              }.alignItems(HorizontalAlign.Start)
            }
          })
        }.layoutWeight(1)
      }.width('100%').alignItems(HorizontalAlign.Start).hitTestBehavior(HitTestMode.None).layoutWeight(1)
    }.height('100%')
  }
}

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐