【HarmonyOS】手势处理
目录
- 一、绑定手势
- 1.绑定手势方法
- gesture
- priorityGesture
- parallelGesture
- 2.设置组件绑定手势
- UIGestureEvent
- addGesture
- addParallelGesture
- removeGestureByTag
- clearGestures
- 二、基础手势
- 1.TapGesture
- 2.LongPressGesture
- 接口
- 事件:
- onAction
- onActionEnd
- onActionCancel
- 3.PanGesture
- 4.PinchGesture
- 接口
- PinchGesture
- 事件
- onActionStart
- onActionUpdate
- onActionEnd
- onActionCancel
- 5.RotationGesture
- 6.SwipeGesture
- 三、组合手势
- 四、手势控制
- 1.自定义手势判定
一、绑定手势
1.绑定手势方法
为组件绑定不同类型的手势事件,并设置事件的响应方法
gesture
绑定手势
gesture(gesture: GestureType, mask?: GestureMask): T
priorityGesture
priorityGesture(gesture: GestureType, mask?: GestureMask): T
绑定优先识别手势
- 默认情况下,子组件优先识别通过gesture绑定的手势,当父组件配置priorityGesture时,父组件优先识别priorityGesture绑定的手势。
- 绑定长按手势时,设置触发长按的最短时间小的组件会优先响应,会忽略priorityGesture设置。
parallelGesture
parallelGesture(gesture: GestureType, mask?: GestureMask): T
绑定可与子组件手势同时触发的手势。手势事件和非冒泡事件。父组件设置paralleGesture,父子组件手势相同的手势事件都可以触发,实现类似冒泡效果。
示例1:父组件优先识别手势和父子组件同时触发手势
@Entry
@Component
struct GestureSettingExample {@State priorityTestValue: string = ''@State parallelTestValue: string = ''build() {Column() {Column() {Text('TapGesture:' + this.priorityTestValue).gesture(TapGesture().onAction((event: GestureEvent) => {this.priorityTestValue += '\nText'}))}.height(200).width(200).padding(20).margin(20).border({ width: 3}).priorityGesture(TapGesture().onAction((event: GestureEvent) => {this.priorityTestValue += '\nColumn'}), GestureMask.IgnoreInternal)Column() {Text('TapGesture:' + this.parallelTestValue).gesture(TapGesture().onAction((event: GestureEvent) => {this.parallelTestValue += '\nText'}))}.height(200).width(200).padding(20).margin(20).border({ width: 3}).parallelGesture(TapGesture().onAction((event: GestureEvent) => {this.parallelTestValue += '\nColumn'}), GestureMask.Normal)}}
}
示例2:实时监测参与滑动手势有效触点数量
@Entry
@Component
struct PanGestureWithFingerCount {@State offsetX: number = 0@State offsetY: number = 0@State positionX: number = 0@State positionY: number = 0//用于记录参与手势的触点数量@State fingerCount: number = 0private panOption: PanGestureOptions = new PanGestureOptions({direction: PanDirection.All,fingers: 1})build() {Column() {Text(`触点数量:${this.fingerCount}`).fontSize(20).margin(10)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')this.fingerCount = event.fingerList?.length || 0 //记录触点数量}).onActionUpdate((event: GestureEvent) => {if (event) {console.info('fingerInfos',JSON.stringify(event.fingerList))this.offsetX = this.positionX + event.offsetXthis.offsetY = this.positionY + event.offsetYthis.fingerCount = event.fingerList?.length || 0 // 更新触点数量,记录下参与当前手势的有效触点的数量}}).onActionEnd((event: GestureEvent) => {this.positionX = this.offsetXthis.positionY = this.offsetYthis.fingerCount = 0console.info('Pan end')}).onActionCancel(() => {this.fingerCount = 0 //手势取消后归零}))Button('切换为双指滑动').onClick(() => {this.panOption.setFingers(2)})}}
}
2.设置组件绑定手势
用于设置组件绑定的手势。可以通过UIGestureEvent对象调用其接口添加或删除手势。
UIGestureEvent
用于设置组件绑定的手势
addGesture
添加手势
addGesture<T>(gesture: GestureHandler<T>, priority?: GesturePriority, mask?: GestureMask): void
addParallelGesture
绑定可与子组件手势同时触发的手势。
addParallelGesture<T>(gesture: GestureHandler<T>, mask?: GestureMask): void
removeGestureByTag
移除该组件上通过modifier绑定的设置为指定标志的手势
removeGestureByTag(tag: string): void
clearGestures
清除该组件上通过modifier绑定的所有手势
clearGestures(): void
二、基础手势
1.TapGesture
支持单击、双击、多次点击事件的识别
示例1:双击手势识别
@Entry
@Component
struct PanGestureWithFingerCount {@State value: string = ''build() {Column() {Text('Click twice').fontSize(28).gesture(TapGesture({count: 2}).onAction((event: GestureEvent) => {if (event) {this.value = JSON.stringify(event.fingerList[0])}}))Text(this.value)}.height(300).width(300).padding(20).border({ width: 3 }).margin(30)}
}
示例2:获取单击手势坐标
@Entry
@Component
struct PanGestureWithFingerCount {@State value: string = ''build() {Column() {Text('Click one').fontSize(28).gesture(TapGesture({count: 1, fingers: 1}).onAction((event: GestureEvent | undefined) => {if (event) {this.value = JSON.stringify(event.fingerList[0])console.info('x:' + event.)}}))Text(this.value)}.height(300).width(300).padding(20).border({ width: 3 }).margin(30)}
}
2.LongPressGesture
用于触发长按手势事件,触发手势的最少手指为1,默认最短时间为500毫秒。可配置duration控制最短长按时长。
接口
LongPressGesture(value?: { fingers?: number; repeat?: boolean; duration?: number })
创建长按手势对象。
当组件默认支持可拖拽时,如Text、TextInput、TextArea、HyperLink、Image和RichEditor等组件。长按手势与拖拽会出现冲突,事件优先级如下:
当长按触发时间小于500毫秒时,系统优先响应长按事件而非拖拽事件。
当长按触发时间达到或超过500毫秒时,系统优先响应拖拽事件而非长按事件。
事件:
onAction
设置长按手势识别成功回调
onActionEnd
设置长按手势结束回调
onActionCancel
设置长按手势取消回调。长按手势识别成功后,接收到触摸取消事件时触发回调。不返回手势事件信息。
示例:
该示例通过LongPressGesture实现了长按手势的识别。
@Entry
@Component
struct PanGestureWithFingerCount {@State count: number = 0build() {Column() {Text('LongPress onAction:' + this.count).fontSize(28).gesture(LongPressGesture({repeat: true}).onAction((event: GestureEvent) => {if (event && event.repeat) {this.count++}}).onActionEnd((event: GestureEvent) => {this.count = 0}))}.height(300).width(300).padding(20).border({ width: 3 }).margin(30)}
}
3.PanGesture
滑动手势事件,当滑动的距离达到设置滑动的最小值时触发滑动手势事件。
@Entry
@Component
struct PanGestureWithFingerCount {@State offsetX: number = 0;@State offsetY: number = 0;@State positionX: number = 0;@State positionY: number = 0;private panOptions: PanGestureOptions = new PanGestureOptions({direction: PanDirection.Left | PanDirection.Right})build() {Column() {Column() {Text('PanGesture offset:\nX:' + this.offsetX + '\nY:' + 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.panOptions).onActionStart((event: GestureEvent) => {console.info('Pan Start')console.info('Pan Start timeStamp is: ' + event.timestamp)}).onActionUpdate((event: GestureEvent) => {if (event) {this.offsetX = event.offsetX + this.positionXthis.offsetY = event.offsetY + this.positionY}}).onActionEnd((event: GestureEvent) => {this.positionX = this.offsetXthis.positionY = this.offsetYconsole.info('Pan End')console.info('Pan End timeStamp is: ' + event.timestamp)}))Button('修改PanGesture触发条件').onClick(() => {this.panOptions.setDirection(PanDirection.All)//this.panOptions.se})}}
}
4.PinchGesture
用于触发捏合手势,最少2指,最多5指
接口
PinchGesture
PinchGesture(value?: { fingers?: number; distance?: number })
设置捏合手势事件。
事件
onActionStart
onActionStart(event: (event: GestureEvent) => void)
Pinch手势识别成功后触发回调。
onActionUpdate
onActionUpdate(event: (event: GestureEvent) => void)
Pinch手势移动过程中回调。
onActionEnd
onActionEnd(event: (event: GestureEvent) => void)
Pinch手势识别成功,当抬起最后一根满足手势触发条件的手指后,触发回调。
onActionCancel
onActionCancel(event: () => void)
Pinch手势识别成功,接收到触摸取消事件触发的回调,不返回手势事件信息。
示例:
@Entry
@Component
struct PinchGestureExample {@State scaleValue: number = 1;@State pinchValue: number = 1;@State pinchX: number = 0;@State pinchY: number = 0;build() {Column() {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 }).scale({ x: this.scaleValue, y: this.scaleValue, z: 1 })// 三指捏合触发该手势事件.gesture(PinchGesture({ fingers: 3 }) // 三指捏合手势,用于缩放操作.onActionStart((event: GestureEvent) => {console.info('Pinch start')}).onActionUpdate((event: GestureEvent) => {if (event) {this.scaleValue = this.pinchValue * event.scalethis.pinchX = event.pinchCenterXthis.pinchY = event.pinchCenterY}}).onActionEnd((event: GestureEvent) => {this.pinchValue = this.scaleValueconsole.info('Pinch end')}))}.width('100%')}
}
5.RotationGesture
用于触发旋转手势,最少需要2指,最多5指,最小改变度数为1度。该手势不支持通过触控板双指旋转操作触发。
示例:
@Entry
@Component
struct RotationGestureExample {@State angle: number = 0;@State rotateValue: number = 0;build() {Column() {Column() {Text('RotationGesture angle:' + this.angle)}.height(200).width(300).padding(20).border({ width: 3 }).margin(80).rotate({ angle: this.angle })// 双指旋转触发该手势事件.gesture(RotationGesture().onActionStart((event: GestureEvent) => {console.info('Rotation start')}).onActionUpdate((event: GestureEvent) => {if (event) {this.angle = this.rotateValue + event.angle}}).onActionEnd((event: GestureEvent) => {this.rotateValue = this.angleconsole.info('Rotation end')}))}.width('100%')}
}
6.SwipeGesture
用于触发快滑手势,滑动速度需大于滑动阈值
@Entry
@Component
struct SwipeGestureExample {@State rotateAngle: number = 0;@State speed: number = 1;build() {Column() {Column() {Text("SwipeGesture speed\n" + this.speed)Text("SwipeGesture angle\n" + this.rotateAngle)}.border({ width: 3 }).width(300).height(200).margin(100).rotate({ angle: this.rotateAngle })// 单指竖直方向快滑时触发该事件.gesture(SwipeGesture({ direction: SwipeDirection.Vertical }).onAction((event: GestureEvent) => {if (event) {this.speed = event.speedthis.rotateAngle = event.angle}}))}.width('100%')}
}
三、组合手势
手势识别组合,即两种及以上手势组合为复合手势,支持顺序识别、并发识别和互斥识别。
@Entry
@Component
struct Index {@State count: number = 0;@State offsetX: number = 0;@State offsetY: number = 0;@State positionX: number = 0;@State positionY: number = 0;@State borderStyles: BorderStyle = BorderStyle.Solid;build() {Column() {Text('sequence gesture\n' + 'LongPress onAction:' + this.count + '\nPanGesture offset:\nX: ' + this.offsetX + '\n' + 'Y: ' + this.offsetY).fontSize(15)}.translate({ x: this.offsetX, y: this.offsetY, z: 0 }).height(150).width(200).padding(20).margin(20).border({ width: 3, style: this.borderStyles }).gesture(GestureGroup(GestureMode.Sequence,LongPressGesture({repeat: true}).onAction((event?: GestureEvent) => {if (event && event.repeat) {this.count++;}console.info('LongPress onAction')}),PanGesture().onActionStart(() => {this.borderStyles = BorderStyle.Dashedconsole.info('pan start')}).onActionUpdate((event: GestureEvent) => {this.offsetX = this.positionX + event.offsetXthis.offsetY = this.positionY + event.offsetYconsole.info('pan update')}).onActionEnd(() => {this.positionX = this.offsetXthis.positionY = this.offsetYthis.borderStyles = BorderStyle.Solid;console.info('pan end')}).onActionCancel(() => {console.info('sequence gesture canceled')})))}
}
四、手势控制
1.自定义手势判定
为组件自提供自定义手势判定能力。开发者根据需要,在手势识别期间,确定是否响应手势。
onGestureJudgeBegin
onGestureJudgeBegin(callback: (gestureInfo: GestureInfo, event: BaseGestureEvent) => GestureJudgeResult): T
为组件绑定自定义手势判定回调。当手势即将成功时,触发用户定义的回调获取结果。
BaseEvent
基础事件类型
示例:自定义手势判定
@Entry
@Component
struct PanGestureWithFingerCount {@State message: string = ''build() {Column() {Row({ space: 20 }) {Text(this.message).width(200).height(80).backgroundColor(Color.Pink).fontSize(25)}.margin(20)}.width('100%').height(200).borderWidth(2).onDragStart(() => {this.message = 'drag'console.log('Drag start')}).gesture(TapGesture().tag('tag1').onAction(() => {this.message = 'TapGesture'})).gesture(LongPressGesture().tag('longPress1').onAction(() => {this.message = 'LongPressGesture'})).gesture(SwipeGesture().tag('swipe1').onAction(() => {this.message = 'SwipeGesture'})).gesture(PanGesture().tag('pan1').onActionStart(() => {this.message = 'PanGesture'})).onGestureJudgeBegin((gestureInfo: GestureInfo, event: BaseGestureEvent) => {if (gestureInfo.type == GestureControl.GestureType.LONG_PRESS_GESTURE) {let longPressEvent = event as LongPressGestureEventconsole.log('repeat' + longPressEvent.repeat);}if (gestureInfo.type == GestureControl.GestureType.SWIPE_GESTURE) {let swipeEvent = event as SwipeGestureEventconsole.log('angle' + swipeEvent.angle)}if (gestureInfo.type == GestureControl.GestureType.PAN_GESTURE) {let PanEvent = event as PanGestureEventconsole.log('velocity' + PanEvent.velocity)}if (gestureInfo.type == GestureControl.GestureType.DRAG) {return GestureJudgeResult.REJECT} else if (gestureInfo.tag == 'longPress1' && event.fingerList.length > 0 && event.fingerList[0].localY < 100) {return GestureJudgeResult.CONTINUE}return GestureJudgeResult.CONTINUE})}