
鸿蒙Next手势详解系列:滑动手势 原创
鸿蒙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 | 滑动手势取消回调 |
手势方向PanDirection有All(所有方向)、Horizontal(水平方向)、Vertical(竖直方向)、Left(向左滑动)、Right(向右滑动)、Up(向上滑动)、Down(向下滑动)、None(任何方向都不可触发滑动)8个值,支持逻辑与(&)和逻辑或(|)运算。
接下来,通过一个简单的滑动演示,直观看一下以上的参数变化:
观察可发现:当单指滑动时
1.每次触发滑动回调之后,X,Y偏移量会重新计算,并且是本次滑动的总距离
2.滑动过程中(localX-offsetX)和(localY-offsetY)的值是不变的,也就是手指点击的位置相对于滑动组件左上角的x,y的偏移量
3.global、display的坐标只和手指的滑动位置有关
看一下设置成双指触发时的滑动回调参数:
观察上图左右手指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%')
}
}
