跃迁引擎

空気を読んだ雨降らないでよ

iOS Research & Development


HarmonyOS - 鸿蒙手势处理及实现原理

一、手势通用事件

点击事件

参数名 类型 必填 说明
event ClickEvent 获得ClickEvent对象。
distanceThreshold number 点击事件移动阈值。当设置的值小于等于0时,会被转化为默认值。 默认值:2^31-1 说明:当手指的移动距离超出开发者预设的移动阈值时,点击识别失败。如果初始化为默认阈值时,手指移动超过组件热区范围,点击识别失败。

ClickEvent对象说明

继承于BaseEvent

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 类型 描述
x number 点击位置相对于被点击元素左边缘的X坐标。 单位:vp 卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
y number 点击位置相对于被点击元素原始区域左上角的Y坐标。 单位:vp 卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
target8+ EventTarget 触发事件的元素对象显示区域。 卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
windowX10+ number 点击位置相对于应用窗口左上角的X坐标。 单位:vp 卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
windowY10+ number 点击位置相对于应用窗口左上角的Y坐标。 单位:vp 卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
displayX10+ number 点击位置相对于应用屏幕左上角的X坐标。 单位:vp 卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
displayY10+ number 点击位置相对于应用屏幕左上角的Y坐标。 单位:vp 卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
screenX(deprecated) number 点击位置相对于应用窗口左上角的X坐标。从API Version 10开始不再维护,建议使用windowX代替。
screenY(deprecated) number 点击位置相对于应用窗口左上角的Y坐标。从API Version 10开始不再维护,建议使用windowY代替。
preventDefault12+ () => void 阻止默认事件。 说明: 该接口仅支持部分组件使用,当前支持组件:RichEditor。 元服务API: 从API version 12开始,该接口支持在元服务中使用。

EventTarget(8+)对象说明

卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 参数类型 描述
area Area 目标元素的区域信息。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import { hilog } from "@kit.PerformanceAnalysisKit"

// 点击事件
@Entry
@Component
struct ClickExample {

@State text: string = ''

onPageShow(): void {
hilog.info(0x0001, 'ClickExample', 'onPageShow')
}

build() {
NavDestination() {
Column() {
Row({ space: 20 }) {
Button('Click').width(100).height(40)
.onClick((event?: ClickEvent) => {
if (event) {
this.text = 'Click Point:' + '\n windowX:' + event.windowX + '\n windowY:' + event.windowY
+ '\n x:' + event.x + '\n y:' + event.y + '\ntarget:' + '\n component globalPos:('
+ event.target.area.globalPosition.x + ',' + event.target.area.globalPosition.y + ')\n width:'
+ event.target.area.width + '\n height:' + event.target.area.height + '\ntimestamp' +
event.timestamp;
}
}, 20)
Button('Click').width(200).height(50)
.onClick((event?: ClickEvent) => {
if (event) {
this.text = 'Click Point:' + '\n windowX:' + event.windowX + '\n windowY:' + event.windowY
+ '\n x:' + event.x + '\n y:' + event.y + '\ntarget:' + '\n component globalPos:('
+ event.target.area.globalPosition.x + ',' + event.target.area.globalPosition.y + ')\n width:'
+ event.target.area.width + '\n height:' + event.target.area.height + '\ntimestamp' +
event.timestamp;
}
}, 20)
}.margin(20)
Text(this.text).margin(15)
}.width('100%')
}
.width('100%')
.height('100%')
}
}

@Builder
export function ClickExampleBuilder(name: string, param: Object) {
ClickExample()
}

img

触摸事件

onTouch

onTouch(event: (event: TouchEvent) => void): T

手指触摸动作触发该回调。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
event TouchEvent 获得TouchEvent对象。

返回值:

类型 说明
T 返回当前组件。

TouchEvent对象说明

继承于BaseEvent。非事件注入场景下,changedTouches是按屏幕显示刷新率重采样的点,touches是按器件刷新率报上来的点,changedTouches的数据可能会和touches里面的不相同。

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 类型 描述
type TouchType 触摸事件的类型。元服务API: 从API version 11开始,该接口支持在元服务中使用。
touches Array<TouchObject> 全部手指信息。元服务API: 从API version 11开始,该接口支持在元服务中使用。
changedTouches Array<TouchObject> 当前发生变化的手指信息。元服务API: 从API version 11开始,该接口支持在元服务中使用。
stopPropagation () => void 阻塞事件冒泡。元服务API: 从API version 11开始,该接口支持在元服务中使用。
preventDefault12+ () => void 阻止默认事件,具体功能暂未实现。元服务API: 从API version 12开始,该接口支持在元服务中使用。

getHistoricalPoints(10+)

getHistoricalPoints(): Array

获取当前帧所有的历史点。不同设备每帧的触摸事件频率不同,且该接口只能在TouchEvent中调用,可以通过该接口获取触发onTouch时当前帧历史点的相关信息。onTouch一帧只会调用一次,若当前帧收到的TouchEvent大于1,会将该帧最后一个点通过onTouch返还,剩余点作为历史点。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 描述
Array<HistoricalPoint> 由历史点组成的数组。

TouchObject对象说明

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 类型 描述
type TouchType 触摸事件的类型。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
id number 手指唯一标识符。 元服务API: 从API version 11开始,该接口支持在元服务中使用。
x number 触摸点相对于事件响应组件的左上角的X坐标。 单位:vp 元服务API: 从API version 11开始,该接口支持在元服务中使用。
y number 触摸点相对于事件响应组件的左上角的Y坐标。 单位:vp 元服务API: 从API version 11开始,该接口支持在元服务中使用。
windowX10+ number 触摸点相对于应用窗口左上角的X坐标。 单位:vp 元服务API: 从API version 11开始,该接口支持在元服务中使用。
windowY10+ number 触摸点相对于应用窗口左上角的Y坐标。 单位:vp 元服务API: 从API version 11开始,该接口支持在元服务中使用。
displayX10+ number 触摸点相对于应用屏幕左上角的X坐标。 单位:vp 元服务API: 从API version 11开始,该接口支持在元服务中使用。
displayY10+ number 触摸点相对于应用屏幕左上角的Y坐标。 单位:vp 元服务API: 从API version 11开始,该接口支持在元服务中使用。
screenX(deprecated) number 触摸点相对于应用窗口左上角的X坐标。 单位:vp 从API version 10开始不再维护,建议使用windowX代替。
screenY(deprecated) number 触摸点相对于应用窗口左上角的Y坐标。 单位:vp 从API version 10开始不再维护,建议使用windowY代替。

HistoricalPoint(10+)对象说明

元服务API: 从API version 11开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 类型 描述
touchObject TouchObject 历史点对应触摸事件的基础信息。
size number 历史点对应触摸事件的手指与屏幕的触摸区域大小。默认值:0
force number 历史点对应触摸事件的压力大小。默认值:0取值范围:[0,65535),压力越大值越大。
timestamp number 历史点对应触摸事件的时间戳。触发事件时距离系统启动的时间间隔。单位:ns

示例

该示例通过按钮设置了触摸事件,手指点击按钮时可获取触摸事件的相关参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 触摸事件
@Entry
@Component
struct TouchExample {
@State text: string = ''
@State eventType: string = ''

build() {
NavDestination() {
Column() {
Button('Touch').height(40).width(100)
.onTouch((event?: TouchEvent) => {
if (event) {
if (event.type === TouchType.Down) {
this.eventType = 'Down'
}
if (event.type === TouchType.Up) {
this.eventType = 'Up'
}
if (event.type === TouchType.Move) {
this.eventType = 'Move'
}
this.text = 'TouchType:' + this.eventType + '\nDistance between touch point and touch element:\nx: '
+ event.touches[0].x + '\n' + 'y: ' + event.touches[0].y + '\nComponent globalPos:('
+ event.target.area.globalPosition.x + ',' + event.target.area.globalPosition.y + ')\nwidth:'
+ event.target.area.width + '\nheight:' + event.target.area.height
}
})
Button('Touch').height(50).width(200).margin(20)
.onTouch((event?: TouchEvent) => {
if (event) {
if (event.type === TouchType.Down) {
this.eventType = 'Down'
}
if (event.type === TouchType.Up) {
this.eventType = 'Up'
}
if (event.type === TouchType.Move) {
this.eventType = 'Move'
}
this.text = 'TouchType:' + this.eventType + '\nDistance between touch point and touch element:\nx: '
+ event.touches[0].x + '\n' + 'y: ' + event.touches[0].y + '\nComponent globalPos:('
+ event.target.area.globalPosition.x + ',' + event.target.area.globalPosition.y + ')\nwidth:'
+ event.target.area.width + '\nheight:' + event.target.area.height
}
})
Text(this.text)
}.width('100%').padding(30)
}
.width('100%')
.height('100%')
}
}

@Builder
export function TouchExampleBuilder() {
TouchExample()
}

img

无障碍悬浮事件

在开启无障碍模式后,Touch事件会转换为无障碍悬浮事件。

onAccessibilityHover

onAccessibilityHover(callback: AccessibilityCallback): T

开启无障碍模式后,单指触摸绑定该回调的组件时触发该回调。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 参数类型 必填 参数描述
callback AccessibilityCallback 提供开启无障碍模式后的无障碍悬浮回调事件,当开启无障碍模式后,单指触摸绑定该回调的组件时触发该回调。

返回值:

类型 说明
T 返回当前组件。

AccessibilityCallback

type AccessibilityCallback = (isHover: boolean, event: AccessibilityHoverEvent) => void

提供开启无障碍模式后的无障碍悬浮回调事件类型。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
isHover boolean 表示开启无障碍模式后,手指是否悬浮在组件上,手指进入时为true, 退出时为false。
event AccessibilityHoverEvent 获得AccessibilityHoverEvent对象。

AccessibilityHoverEvent对象说明

继承于BaseEvent

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 属性类型 描述
type AccessibilityHoverType 无障碍悬浮动作。
x number 手指位置相对于当前组件左上角的x轴坐标。单位:vp
y number 手指位置相对于当前组件左上角的y轴坐标。单位:vp
windowX number 手指位置相对于应用窗口左上角的x轴坐标。单位:vp
windowY number 手指位置相对于应用窗口左上角的y轴坐标。单位:vp
displayX number 手指位置相对于应用屏幕左上角的x轴坐标。单位:vp
displayY number 手指位置相对于应用屏幕左上角的y轴坐标。单位:vp

AccessibilityHoverType

定义无障碍悬浮类型。

名称 描述
HOVER_ENTER 0 手指按下时触发。
HOVER_MOVE 1 触摸移动时触发。
HOVER_EXIT 2 抬手触发。
HOVER_CANCEL 3 打断取消当前触发的事件。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// xxx.ets
@Entry
@Component
struct OnAccessibilityHoverEventExample {
@State hoverText: string = 'no hover';
@State color: Color = Color.Blue;

build() {
Column({ space: 20 }) {
Button(this.hoverText)
.width(180).height(80)
.backgroundColor(this.color)
.onAccessibilityHover((isHover: boolean, event: AccessibilityHoverEvent) => {
// 通过onAccessibilityHover事件动态修改按钮在是否有鼠标悬浮时的文本内容与背景颜色
if (isHover) {
this.hoverText = 'hover';
this.color = Color.Pink;
} else {
this.hoverText = 'no hover';
this.color = Color.Blue;
}
})
}.padding({ top: 30 }).width('100%')
}
}

二、通用属性

动态手势设置

动态设置组件绑定的手势,支持开发者在属性设置时使用if/else语法。

gestureModifier

gestureModifier(modifier: GestureModifier)

动态设置组件绑定的手势。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
modifier GestureModifier 在当前组件上,动态设置组件绑定的手势,支持使用if/else语法。modifier: 手势修改器,开发者需要自定义class实现GestureModifier接口。

GestureModifier

开发者需要自定义class实现GestureModifier接口。

applyGesture

applyGesture(event: UIGestureEvent): void

组件需要绑定的手势。

开发者可根据需要自定义实现这个方法,对组件设置需要绑定的手势,支持使用if/else语法进行动态设置。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

参数

参数名 类型 说明
event UIGestureEvent UIGestureEvent对象,用于设置组件需要绑定的手势。

示例

该示例通过gestureModifier动态设置组件绑定的手势。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class MyButtonModifier implements GestureModifier {
supportDoubleTap: boolean = true

actionBack?: ((log: string) => void)

applyGesture(event: UIGestureEvent): void {
if (this.supportDoubleTap) {
event.addGesture(
new TapGestureHandler({ count: 2, fingers: 1 })
.tag("aaa")
.onAction((event: GestureEvent) => {
if (this.actionBack) {
this.actionBack("button tap")
}
})
)
} else {
event.addGesture(
new PanGestureHandler()
.onActionStart(()=>{
if (this.actionBack) {
this.actionBack("Pan start")
}
})
.onActionEnd(() =>{
if (this.actionBack) {
this.actionBack("Pan end")
}
})
.onActionCancel(() => {
if (this.actionBack) {
this.actionBack("Pan cancel")
}
})

)
}
}
}

// 动态手势设置
@Entry
@Component
struct ActiveGesture {
@State modifier: MyButtonModifier = new MyButtonModifier()
@State text: string = ''

onPageShow(): void {

}

aboutToAppear(): void {
this.modifier.actionBack = (log: string) => {
console.log("actionBack " + log)
this.text = log
this.modifier.supportDoubleTap = !this.modifier.supportDoubleTap
}
}

build() {
NavDestination() {
Row() {
Column() {
Column()
.gestureModifier(this.modifier)
.width(500)
.height(200)
.backgroundColor(Color.Blue)

Text(this.text)
.fontColor(Color.Gray)
.fontSize(15)
.width("100%")
.height(30)
.backgroundColor(Color.Yellow)
}
.width('100%')
}
.height('100%')
}.width("100%")
.height("100%")
}
}

@Builder
export function ActiveGestureBuilder() {
ActiveGesture()
}

触摸热区设置

适用于支持通用点击事件、通用触摸事件、通用手势处理的组件。

responseRegion

responseRegion(value: Array | Rectangle)

设置一个或多个触摸热区。

卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
value Array<Rectangle> | Rectangle 设置一个或多个触摸热区,包括位置和大小。默认触摸热区为整个组件,默认值:{x:0,y:0,width:’100%’,height:’100%’} 卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。

Rectangle对象说明

卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 类型 必填 描述
x Length 触摸点相对于组件左上角的x轴坐标。默认值:0vp
y Length 触摸点相对于组件左上角的y轴坐标。默认值:0vp
width Length 触摸热区的宽度。默认值:’100%’
height Length 触摸热区的高度。默认值:’100%’

说明

x和y可以设置正负值百分比。当x设置为’100%’时表示热区往右偏移组件本身宽度大小,当x设置为’-100%’时表示热区往左偏移组件本身宽度大小。当y设置为’100%’时表示热区往下偏移组件本身高度大小,当y设置为’-100%’时表示热区往上偏移组件本身高度大小。

width和height只能设置正值百分比。width:’100%’表示热区宽度设置为该组件本身的宽度。比如组件本身宽度是100vp,那么’100%’表示热区宽度也为100vp。height:’100%’表示热区高度设置为该组件本身的高度。

百分比相对于组件自身宽高进行计算。

示例

该示例通过responseRegion对按钮设置触摸热区响应点击事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// 触摸热区设置
@Entry
@Component
struct TouchTargetExample {
@State text: string = ""

build() {
NavDestination() {
Column({ space: 20 }) {
Text("{x:0,y:0,width:'50%',height:'100%'}")
// 热区宽度为按钮的一半,点击右侧无响应
Button("button1")
.responseRegion({
x: 0,
y: 0,
width: '50%',
height: '100%'
})
.onClick(() => {
this.text = 'button1 clicked'
})

// 为一个组件添加多个热区
Text("[{x:'100%',y:0,width:'50%',height:'100%'}," +
"\n{ x: 0, y: 0, width: '50%', height: '100%' }]")
Button("button2")
.responseRegion([
{
x: '100%',
y: 0,
width: '50%',
height: '100%'
}, // 第一个热区宽度为按钮的一半,点击按钮右侧宽度一半区域,点击事件生效
{
x: 0,
y: 0,
width: '50%',
height: '100%'
}// 第二个热区宽度为按钮的一半,点击button2左半边,点击事件生效
])
.onClick(() => {
this.text = 'button2 clicked'
})
// 热区大小为整个按钮,且下移一个按钮高度,点击button3下方按钮大小区域,点击事件生效
Text("{x:0,y:'100%',width:'100%',height:'100%'}")
Button("button3")
.responseRegion({
x: 0,
y: '100%',
width: '100%',
height: '100%'
})
.onClick(() => {
this.text = 'button3 clicked'
})

Text(this.text).margin({ top: 50 })
}.width('100%').margin({ top: 10 })
}.width("100%")
.height("100%")
}
}

@Builder
export function TouchTargetExampleBuilder() {
TouchTargetExample()
}

触摸测试控制

设置组件的触摸测试类型。ArkUI开发框架在处理触屏事件时,会在触屏事件触发前,进行按压点和组件区域的触摸测试来收集需要响应触屏事件的组件,然后基于触摸测试结果分发相应的触屏事件。hitTestBehavior属性可以设置不同的触摸测试响应模式,影响组件的触摸测试收集结果,最终影响后续的触屏事件分发,具体影响参考HitTestMode枚举说明。

说明

  • 从API Version 9开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
  • 当Stack组件中有多个节点触摸区域重叠时,如两个节点,默认只会对显示在最上层的节点做触摸测试,若需要显示在下层的节点触发触摸测试,请给显示在上层的节点设置hitTestBehavior为HitTestMode.Transparent。

hitTestBehavior

hitTestBehavior(value: HitTestMode)

设置组件的触摸测试类型。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
value HitTestMode 设置当前组件的触摸测试类型。默认值: HitTestMode.Default

HitTestMode枚举说明

名称 枚举值 描述
Default 0 默认触摸测试效果,自身和子节点都响应触摸测试,但会阻塞兄弟节点的触摸测试。不会影响祖先节点的触摸测试。
Block 1 自身响应触摸测试,阻塞子节点和兄弟节点的触摸测试。会阻塞祖先节点的触摸测试。
Transparent 2 自身和子节点都响应触摸测试,不会阻塞兄弟节点的触摸测试。不会影响祖先节点的触摸测试。
None 3 自身不响应触摸测试,不会阻塞子节点和兄弟节点的触摸测试。不会影响祖先节点的触摸测试。

示例

该示例通过设置不同的HitTestMode值演示了Block和Transparent的触摸类型效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 触摸测试控制
@Entry
@Component
struct HitTestBehaviorExample {
build() {
NavDestination() {
// outer stack
Stack() {
Button('outer button')
.onTouch((event) => {
console.info('outer button touched type: ' + (event as TouchEvent).type)
})
// inner stack
Stack() {
Button('inner button')
.onTouch((event) => {
console.info('inner button touched type: ' + (event as TouchEvent).type)
})
}
.width("100%").height("100%")
.hitTestBehavior(HitTestMode.Block)
.onTouch((event) => {
console.info('stack touched type: ' + (event as TouchEvent).type)
})

Text('Transparent')
.hitTestBehavior(HitTestMode.Transparent)
.width("100%").height("100%")
.onTouch((event) => {
console.info('text touched type: ' + (event as TouchEvent).type)
})
}.width(300).height(300)
}
.width("100%")
.height("100%")
}
}

@Builder
export function HitTestBehaviorExampleBuilder() {
HitTestBehaviorExample()
}

三、手势处理

onClick > Gesture 触发,onClick 会先吞噬所有触摸的事件

绑定手势方法

通过如下属性给组件绑定手势识别,手势识别成功后可以通过事件回调通知组件。

可以通过触摸热区指定可识别手势的区域。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 参数类型 默认值 描述
gesture gesture: GestureType,mask?: GestureMask gesture: -,mask: GestureMask.Normal 绑定手势。- gesture: 绑定的手势类型。- mask: 事件响应设置。
priorityGesture gesture: GestureType,mask?: GestureMask gesture: -,mask: GestureMask.Normal 绑定优先识别手势。- gesture: 绑定的手势类型。- mask: 事件响应设置。1、默认情况下,子组件优先识别通过gesture绑定的手势,当父组件配置priorityGesture时,父组件优先识别priorityGesture绑定的手势。2、长按手势时,设置触发长按的最短时间小的组件会优先响应,会忽略priorityGesture设置。
parallelGesture gesture: GestureType,mask?: GestureMask gesture: -,mask: GestureMask.Normal 绑定可与子组件手势同时触发的手势。- gesture: 绑定的手势类型。- mask: 事件响应设置。手势事件为非冒泡事件。父组件设置parallelGesture时,父子组件相同的手势事件都可以触发,实现类似冒泡效果。

GestureType

元服务API: 从API version 12开始,该接口支持在元服务中使用。

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

GestureMask枚举说明

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 描述
Normal 不屏蔽子组件的手势,按照默认手势识别顺序进行识别。
IgnoreInternal 屏蔽子组件的手势,包括子组件上系统内置的手势,如子组件为List组件时,内置的滑动手势同样会被屏蔽。 若父子组件区域存在部分重叠,则只会屏蔽父子组件重叠的部分。

响应手势事件

组件通过手势事件绑定不同GestureType的手势对象,各手势对象在响应手势操作的事件回调中提供手势相关信息。下面通过TapGesture手势对象的onAction事件响应点击事件,获取事件相关信息。其余手势对象的事件定义见各个手势对象章节。 若需绑定多种手势请使用 组合手势

TapGesture事件说明

名称 功能描述
onAction((event:GestureEvent) => void) Tap手势识别成功回调。

GestureEvent对象说明

继承于BaseEvent

元服务API: 从API version 11开始,该接口支持在元服务中使用。

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

SourceType枚举说明

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 描述
Unknown 未知设备。
Mouse 鼠标。
TouchScreen 触摸屏。

FingerInfo对象说明(8+)

名称 类型 描述
id number 手指的索引编号。元服务API: 从API version 11开始,该接口支持在元服务中使用。
globalX number 相对于应用窗口左上角的x轴坐标,单位为vp。元服务API: 从API version 11开始,该接口支持在元服务中使用。
globalY number 相对于应用窗口左上角的y轴坐标,单位为vp。元服务API: 从API version 11开始,该接口支持在元服务中使用。
localX number 相对于当前组件元素原始区域左上角的x轴坐标,单位为vp。元服务API: 从API version 11开始,该接口支持在元服务中使用。
localY number 相对于当前组件元素原始区域左上角的y轴坐标,单位为vp。元服务API: 从API version 11开始,该接口支持在元服务中使用。
displayX12+ number 相对于屏幕左上角的x轴坐标,单位为vp。元服务API: 从API version 12开始,该接口支持在元服务中使用。
displayY12+ number 相对于屏幕左上角的y轴坐标,单位为vp。元服务API: 从API version 12开始,该接口支持在元服务中使用。

SourceTool枚举说明(9+)

名称 描述
Unknown 未知输入源。元服务API: 从API version 11开始,该接口支持在元服务中使用。
Finger 手指输入。元服务API: 从API version 11开始,该接口支持在元服务中使用。
Pen 手写笔输入。元服务API: 从API version 11开始,该接口支持在元服务中使用。
Mouse12+ 鼠标输入。元服务API: 从API version 12开始,该接口支持在元服务中使用。
Touchpad12+ 触控板输入。触控板单指输入被视为鼠标输入操作。元服务API: 从API version 12开始,该接口支持在元服务中使用。
Joystick12+ 手柄输入。元服务API: 从API version 12开始,该接口支持在元服务中使用。

示例

该示例通过配置priorityGesture和parallelGesture分别实现了父组件优先识别手势和父子组件同时触发手势。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 绑定手势方法
@Entry
@Component
struct GestureSettingsExample {
@State priorityTestValue: string = ''
@State parallelTestValue: string = ''

build() {
NavDestination() {
Column() {
Column() {
Text('TapGesture:' + this.priorityTestValue).fontSize(28)
.gesture(
TapGesture()
.onAction((event: GestureEvent) => {
this.priorityTestValue += '\nText'
}))
}
.height(200)
.width(250)
.padding(20)
.margin(20)
.border({ width: 3 })
// 设置为priorityGesture时,点击文本会忽略Text组件的TapGesture手势事件,优先识别父组件Column的TapGesture手势事件
.priorityGesture(
TapGesture()
.onAction((event: GestureEvent) => {
this.priorityTestValue += '\nColumn1'
}), GestureMask.IgnoreInternal)

Column() {
Text('TapGesture:' + this.parallelTestValue).fontSize(28)
.gesture(
TapGesture()
.onAction((event: GestureEvent) => {
this.parallelTestValue += '\nText'
}))
}
.height(200)
.width(250)
.padding(20)
.margin(20)
.border({ width: 3 })
// 设置为parallelGesture时,点击文本会同时触发子组件Text与父组件Column的TapGesture手势事件
.parallelGesture(
TapGesture()
.onAction((event: GestureEvent) => {
this.parallelTestValue += '\nColumn2'
}), GestureMask.Normal)
}
}.width("100%")
.height("100%")
}
}

@Builder
export function GestureSettingsExampleBuilder() {
GestureSettingsExample()
}

TapGesture

支持单击、双击和多次点击事件的识别。

说明

从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

接口

TapGesture(value?: TapGestureParameters)

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名称 参数类型 必填 参数描述
value TapGestureParameters 点击手势的相关参数。

TapGestureParameters(12+)对象说明

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 类型 必填 描述
count number 识别的连续点击次数。当设置的值小于1或不设置时,会被转化为默认值。默认值:1说明:1. 当配置多击时,上一次的最后一根手指抬起和下一次的第一根手指按下的超时时间为300毫秒。2. 当上次点击的位置与当前点击的位置距离超过60vp时,手势识别失败。在多指情况下,点击的位置为所有参与手势响应手指的平均位置。
fingers number 触发点击的手指数,最小为1指, 最大为10指。当设置小于1的值或不设置时,会被转化为默认值。默认值:1说明:1. 当配置多指时,第一根手指按下后300毫秒内未有足够的手指数按下,手势识别失败;手指抬起时,抬起后剩余的手指数小于阈值时开始计时,如300ms内未全部抬起则手势识别失败。2. 实际点击手指数超过配置值,手势识别成功。
distanceThreshold number 点击手势移动阈值。当设置的值小于等于0或不设置时,会被转化为默认值。默认值:2^31-1说明:当手指的移动距离超出开发者预设的移动阈值时,点击识别失败。如果初始化为默认阈值时,手指移动超过组件热区范围,点击识别失败。

事件

名称 功能描述
onAction(event: (event: GestureEvent) => void) Tap手势识别成功回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。

属性

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 类型 描述
tag11+ string 设置Tap手势标志,用于自定义手势判定时区分绑定的手势。

示例

该示例通过TapGesture实现了双击手势的识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// xxx.ets
@Entry
@Component
struct TapGestureExample {
@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(200)
.width(300)
.padding(20)
.border({ width: 3 })
.margin(30)
}
}

img

LongPressGesture

用于触发长按手势事件,触发长按手势的最少手指数为1,最短长按时间为500毫秒。

说明

从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

接口

LongPressGesture(value?: { fingers?: number, repeat?: boolean, duration?: number })

当组件默认支持可拖拽时,如Text、TextInput、TextArea、HyperLink、Image和RichEditor等组件。长按手势与拖拽会出现冲突,事件优先级如下:

长按触发时间 < 500ms,长按事件优先拖拽事件响应。

长按触发时间 >= 500ms,拖拽事件优先长按事件响应。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

参数:

参数名称 参数类型 必填 参数描述
fingers number 触发长按的最少手指数,最小为1指, 最大取值为10指。默认值:1说明:手指按下后若发生超过15px的移动,则判定当前长按手势识别失败。
repeat boolean 是否连续触发事件回调。默认值:false
duration number 触发长按的最短时间,单位为毫秒(ms)。默认值:500说明:设置小于等于0时,按照默认值500处理。

事件

名称 功能描述
onAction(event:(event: GestureEvent) => void) LongPress手势识别成功回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionEnd(event:(event: GestureEvent) => void) LongPress手势识别成功,最后一根手指抬起后触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionCancel(event: () => void) LongPress手势识别成功,接收到触摸取消事件触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。

属性

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 类型 描述
tag11+ string 设置LongPress手势标志,用于自定义手势判定时区分绑定的手势。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 长按手势
@Entry
@Component
struct LongPressGestureExample {
@State count: number = 0

build() {
NavDestination() {
Column() {
Text('LongPress onAction:' + this.count).fontSize(28)// 单指长按文本触发该手势事件
.gesture(
LongPressGesture({ repeat: true })// 由于repeat设置为true,长按动作存在时会连续触发,触发间隔为duration(默认值500ms)
.onAction((event: GestureEvent) => {
if (event && event.repeat) {
this.count++
}
})// 长按动作一结束触发
.onActionEnd((event: GestureEvent) => {
this.count = 0
})
)
}
.height(200)
.width(300)
.padding(20)
.border({ width: 3 })
.margin(30)
}.width("100%")
.height("100%")
}
}

@Builder
export function LongPressGestureExampleBuilder() {
LongPressGestureExample()
}

img

PanGesture

滑动手势事件,当滑动的最小距离达到设定的最小值时触发滑动手势事件。

说明

从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

接口

PanGesture(value?: { fingers?: number, direction?: PanDirection, distance?: number } | PanGestureOptions)

元服务API: 从API version 11开始,该接口支持在元服务中使用。

参数:

参数名称 参数类型 必填 参数描述
fingers number 用于指定触发拖动的最少手指数,最小为1指, 最大取值为10指。默认值:1取值范围:[1,10]说明:当设置的值小于1或不设置时,会被转化为默认值。
direction PanDirection 用于指定触发拖动的手势方向,此枚举值支持逻辑与(&)和逻辑或(|)运算。默认值:PanDirection.All
distance number 用于指定触发拖动手势事件的最小拖动距离,单位为vp。默认值:5说明:Tabs组件滑动与该拖动手势事件同时存在时,可将distance值设为1,使拖动更灵敏,避免造成事件错乱。当设定的值小于0时,按默认值5处理。

PanDirection枚举说明

与SwipeDirection不同,PanDirection没有角度限制。

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 描述
All 所有方向。
Horizontal 水平方向。
Vertical 竖直方向。
Left 向左拖动。
Right 向右拖动。
Up 向上拖动。
Down 向下拖动。
None 任何方向都不可触发拖动手势事件。

PanGestureOptions

通过PanGestureOptions对象接口可以动态修改平移手势识别器的属性,从而避免通过状态变量修改属性(状态变量修改会导致UI刷新)。

PanGestureOptions(value?: { fingers?: number, direction?: PanDirection, distance?: number })

元服务API: 从API version 11开始,该接口支持在元服务中使用。

参数:

参数名称 参数类型 必填 参数描述
fingers number 用于指定触发滑动的最少手指数,最小为1指, 最大取值为10指。默认值:1
direction PanDirection 用于指定设置滑动方向,此枚举值支持逻辑与(&)和逻辑或(|)运算。默认值:PanDirection.All
distance number 用于指定触发拖动手势事件的最小拖动距离,单位为vp。默认值:5说明:Tabs组件滑动与该拖动手势事件同时存在时,可将distance值设为1,使拖动更灵敏,避免造成事件错乱。当设定的值小于0时,按默认值5处理。建议设置合理的拖动距离,拖动距离设置过大时会导致滑动不跟手(响应时延慢)的问题。

接口

名称 功能描述
setDirection(value: PanDirection) 设置direction属性。元服务API: 从API version 11开始,该接口支持在元服务中使用。
setDistance(value: number) 设置distance属性。元服务API: 从API version 11开始,该接口支持在元服务中使用。
setFingers(value: number) 设置fingers属性。元服务API: 从API version 11开始,该接口支持在元服务中使用。
getDirection()12+: PanDirection 获取direction属性。元服务API: 从API version 12开始,该接口支持在元服务中使用。

事件

名称 功能描述
onActionStart(event: (event: GestureEvent) => void) Pan手势识别成功回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionUpdate(event: (event: GestureEvent) => void) Pan手势移动过程中回调。fingerList为多根手指时,该回调监听每次只会更新一根手指的位置信息。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionEnd(event: (event: GestureEvent) => void) Pan手势识别成功,手指抬起后触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionCancel(event: () => void) Pan手势识别成功,接收到触摸取消事件触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。

属性

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 类型 描述
tag11+ string 设置Pan手势标志,用于自定义手势判定时区分绑定的手势。

示例

该示例通过PanGesture实现了单指/双指滑动手势的识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@Entry
@Component
struct PanGestureExample {
@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 })

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')
})
)

Button('修改PanGesture触发条件')
.onClick(() => {
// 将PanGesture手势事件触发条件改为双指以任意方向滑动
this.panOption.setDirection(PanDirection.All)
this.panOption.setFingers(2)
})
}
}
}

示意图:

向左滑动:

img

点击按钮修改PanGesture触发条件,双指向左下方滑动:

img

PinchGesture

用于触发捏合手势,触发捏合手势的最少手指为2指,最大为5指,最小识别距离为5vp。

说明

从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

接口

PinchGesture(value?: { fingers?: number, distance?: number })

元服务API: 从API version 11开始,该接口支持在元服务中使用。

参数:

参数名称 参数类型 必填 参数描述
fingers number 触发捏合的最少手指数, 最小为2指,最大为5指。默认值:2触发手势手指可以多于fingers数目,但只有先落下的与fingers相同数目的手指参与手势计算。
distance number 最小识别距离,单位为vp。默认值:5说明:当识别距离的值小于等于0时,会被转化为默认值。

事件

名称 功能描述
onActionStart(event:(event: GestureEvent) => void) Pinch手势识别成功回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionUpdate(event:(event: GestureEvent) => void) Pinch手势移动过程中回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionEnd(event:(event: GestureEvent) => void) Pinch手势识别成功,手指抬起后触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionCancel(event: () => void) Pinch手势识别成功,接收到触摸取消事件触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。

属性

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 类型 描述
tag11+ string 设置Pinch手势标志,用于自定义手势判定时区分绑定的手势。

示例

该示例通过配置PinchGesture实现了三指捏合手势的识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 三指捏合手势
@Entry
@Component
struct PinchGestureExample {
@State scaleValue: number = 1
@State pinchValue: number = 1
@State pinchX: number = 0
@State pinchY: number = 0

build() {
NavDestination() {
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.scale
this.pinchX = event.pinchCenterX
this.pinchY = event.pinchCenterY
}
})
.onActionEnd((event: GestureEvent) => {
this.pinchValue = this.scaleValue
console.info('Pinch end')
})
)
}.width('100%')
}
.width("100%")
.height("100%")
}
}

@Builder
export function PinchGestureExampleBuilder() {
PinchGestureExample()
}

img

RotationGesture

用于触发旋转手势事件,触发旋转手势的最少手指为2指,最大为5指,最小改变度数为1度。

说明

从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

接口

RotationGesture(value?: { fingers?: number, angle?: number })

元服务API: 从API version 11开始,该接口支持在元服务中使用。

参数:

参数名称 参数类型 必填 参数描述
fingers number 触发旋转的最少手指数, 最小为2指,最大为5指。默认值:2触发手势手指可以多于fingers数目,但只有先落下的两指参与手势计算。
angle number 触发旋转手势的最小改变度数,单位为deg。默认值:1说明:当改变度数的值小于等于0或大于360时,会被转化为默认值。

事件

名称 功能描述
onActionStart(event:(event: GestureEvent) => void) Rotation手势识别成功回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionUpdate(event:(event: GestureEvent) => void) Rotation手势移动过程中回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionEnd(event:(event: GestureEvent) => void) Rotation手势识别成功,手指抬起后触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。
onActionCancel(event: () => void) Rotation手势识别成功,接收到触摸取消事件触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。

属性

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 类型 描述
tag11+ string 设置Rotation手势标志,用于自定义手势判定时区分绑定的手势。

示例

该示例通过配置RotationGesture实现了双指旋转手势的识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 旋转手势
@Entry
@Component
struct RotationGestureExample {
@State angle: number = 0
@State rotateValue: number = 0

build() {
NavDestination() {
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.angle
console.info('Rotation end')
})
)
}.width('100%')
}
.width("100%")
.height("100%")
}
}

@Builder
export function RotationGestureExampleBuilder() {
RotationGestureExample()
}

img

SwipeGesture

用于触发滑动事件,滑动速度大于100vp/s时可识别成功。

说明

从API Version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

接口

SwipeGesture(value?: { fingers?: number, direction?: SwipeDirection, speed?: number })

元服务API: 从API version 11开始,该接口支持在元服务中使用。

参数:

参数名称 参数类型 必填 参数描述
fingers number 触发滑动的最少手指数,默认为1,最小为1指,最大为10指。默认值:1
direction SwipeDirection 触发滑动手势的滑动方向。默认值:SwipeDirection.All
speed number 识别滑动的最小速度。默认值:100VP/s说明:当滑动速度的值小于等于0时,会被转化为默认值。

SwipeDirection枚举说明

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 描述
All 所有方向。
Horizontal 水平方向,手指滑动方向与x轴夹角小于45度时触发。
Vertical 竖直方向,手指滑动方向与y轴夹角小于45度时触发。
None 任何方向均不可触发。

事件

名称 功能描述
onAction(event:(event: GestureEvent) => void) Swipe手势识别成功回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。

属性

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 类型 描述
tag11+ string 设置Swipe手势标志,用于自定义手势判定时区分绑定的手势。

示例

该示例通过配置SwipeGesture实现了滑动手势的识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 清扫手势
@Entry
@Component
struct SwipeGestureExample {
@State rotateAngle: number = 0
@State speed: number = 1

build() {
NavDestination() {
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.speed
this.rotateAngle = event.angle
}
})
)
}.width('100%')
}.width("100%")
.height("100%")
}
}

@Builder
export function SwipeGestureExampleBuilder() {
SwipeGestureExample()
}

img

组合手势

手势识别组合,即多种手势组合为复合手势,支持连续识别、并行识别和互斥识别。

说明

从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

接口

GestureGroup(mode: GestureMode, …gesture: GestureType[])

元服务API: 从API version 11开始,该接口支持在元服务中使用。

参数:

参数名 参数类型 必填 参数描述
mode GestureMode 设置组合手势识别模式。默认值:GestureMode.Sequence
gesture TapGesture| LongPressGesture| PanGesture| PinchGesture| RotationGesture| SwipeGesture| GestureGroup 设置1个或者多个基础手势类型时,这些手势会被识别为组合手势。若此参数不填则组合手势识别功能不生效。说明:当需要为一个组件同时添加单击和双击手势时,可在组合手势中添加两个TapGesture,需要双击手势在前,单击手势在后,否则不生效。

GestureMode枚举说明

元服务API: 从API version 11开始,该接口支持在元服务中使用。

名称 描述
Sequence 顺序识别,按照手势的注册顺序识别手势,直到所有手势识别成功。若有一个手势识别失败,后续手势识别均失败。顺序识别手势组仅有最后一个手势可以响应onActionEnd。
Parallel 并发识别,注册的手势同时识别,直到所有手势识别结束,手势识别互相不影响。
Exclusive 互斥识别,注册的手势同时识别,若有一个手势识别成功,则结束手势识别。

事件

名称 功能描述
onCancel(event: () => void) 顺序组合手势(GestureMode.Sequence)取消后触发回调。元服务API: 从API version 11开始,该接口支持在元服务中使用。

示例

该示例通过配置GestureGroup实现了长按和拖动的组合手势顺序识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@Entry
@Component
struct GestureGroupExample {
@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.Dashed
console.info('pan start')
})
.onActionUpdate((event?: GestureEvent) => {
if (event) {
this.offsetX = this.positionX + event.offsetX
this.offsetY = this.positionY + event.offsetY
}
console.info('pan update')
})
.onActionEnd(() => {
this.positionX = this.offsetX
this.positionY = this.offsetY
this.borderStyles = BorderStyle.Solid
console.info('pan end')
})
)
.onCancel(() => {
console.info('sequence gesture canceled')
})
)
}
}

示意图:

按顺序首先触发长按事件:

img

按顺序首先触发长按事件,长按事件识别结束之后,其次触发拖动事件,向右下方拖动:

img

自定义手势判定

为组件提供自定义手势判定能力。开发者可根据需要,在手势识别期间,决定是否响应手势。

说明

从API Version 11开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

onGestureJudgeBegin

onGestureJudgeBegin(callback: (gestureInfo: GestureInfo, event: BaseGestureEvent) => GestureJudgeResult): T

元服务API: 从API version 12开始,该接口支持在元服务中使用。

参数:

参数名 参数类型 必填 参数描述
callback (gestureInfo: GestureInfo, event: BaseGestureEvent) => GestureJudgeResult 给组件绑定自定义手势判定回调,当绑定到该组件的手势被接受时,会触发用户定义的回调来获取结果。

返回值:

类型 说明
T 返回当前组件。

GestureJudgeResult(11+)

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 描述
CONTINUE 不影响系统手势判定流程。
REJECT 对于用户自定义的手势判定结果为失败。

GestureInfo对象说明

元服务API: 从API version 12开始,该接口支持在元服务中使用。

名称 类型 描述
tag string 手势标记。说明:如果未设置事件标识tag属性的情况下,此处tag不返回或者返回undefined。
type GestureControl.GestureType 手势类型。说明:当手势为未暴露类型的系统内置手势事件时,type的值为-1。
isSystemGesture boolean 判断当前手势是否是组件自带的手势。默认值:false

GestureType(11+)

元服务API: 从API version 11开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 描述
TAP_GESTURE 0 点击手势
LONG_PRESS_GESTURE 1 长按手势
PAN_GESTURE 2 拖动手势
PINCH_GESTURE 3 捏合手势
SWIPE_GESTURE 4 滑动手势
ROTATION_GESTURE 5 旋转手势
DRAG 6 拖拽
CLICK 7 点击

BaseEvent对象说明

名称 类型 描述
target EventTarget 触发手势事件的元素对象显示区域。卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 11开始,该接口支持在元服务中使用。
timestamp number 事件时间戳,触发事件时距离系统启动的时间间隔。单位:ns卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 11开始,该接口支持在元服务中使用。
source SourceType 事件输入设备。卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 11开始,该接口支持在元服务中使用。
pressure number 按压的压力大小。默认值:0取值范围:[0,1],典型值0.913168,压感大小与数值正相关。卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 11开始,该接口支持在元服务中使用。
tiltX number 手写笔在设备平面上的投影与设备平面X轴的夹角。卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 11开始,该接口支持在元服务中使用。
tiltY number 手写笔在设备平面上的投影与设备平面Y轴的夹角。卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 11开始,该接口支持在元服务中使用。
sourceTool SourceTool 事件输入源。卡片能力: 从API version 9开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 11开始,该接口支持在元服务中使用。
axisHorizontal12+ number 水平轴值。说明:当前仅在由鼠标滚轮或者触控板双指滑动场景下触发的Pan手势中可以获取。卡片能力: 从API version 12开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 12开始,该接口支持在元服务中使用。
axisVertical12+ number 垂直轴值。说明:当前仅在由鼠标滚轮或者触控板双指滑动场景下触发的Pan手势中可以获取。卡片能力: 从API version 12开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 12开始,该接口支持在元服务中使用。
getModifierKeyState12+ (Array) => bool 获取功能键按压状态。报错信息请参考以下错误码。支持功能键 ‘Ctrl’|’Alt’|’Shift’|’Fn’,设备外接带Fn键的键盘不支持Fn键查询。元服务API: 从API version 12开始,该接口支持在元服务中使用。
deviceId12+ number 触发当前事件的输入设备ID。卡片能力: 从API version 12开始,该接口支持在ArkTS卡片中使用。元服务API: 从API version 12开始,该接口支持在元服务中使用。

错误码

以下错误码详细介绍请参考通用错误码

错误码ID 错误信息
401 Parameter error. Possible causes: 1. Incorrect parameter types. 2. Parameter verification failed.

BaseGestureEvent对象说明

继承于BaseEvent

元服务API: 从API version 12开始,该接口支持在元服务中使用。

名称 类型 描述
fingerList [FingerInfo] 触发事件的所有手指信息。

TapGestureEvent对象说明

继承于BaseGestureEvent。可将该对象作为onGestureJudgeBegin的event参数来传递。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

LongPressGestureEvent对象说明

继承于BaseGestureEvent。可将该对象作为onGestureJudgeBegin的event参数来传递。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

名称 类型 描述
repeat boolean 是否为重复触发事件。

PanGestureEvent对象说明

继承于BaseGestureEvent。可将该对象作为onGestureJudgeBegin的event参数来传递。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

名称 类型 描述
offsetX number 手势事件x轴相对当前组件元素原始区域的偏移量,单位为vp,从左向右滑动offsetX为正,反之为负。
offsetY number 手势事件y轴相对当前组件元素原始区域的偏移量,单位为vp,从上向下滑动offsetY为正,反之为负。
velocityX number 获取当前手势的x轴方向速度。坐标轴原点为屏幕左上角,分正负方向速度,从左往右为正,反之为负。单位为vp/s。
velocityY number 获取当前手势的y轴方向速度。坐标轴原点为屏幕左上角,分正负方向速度,从上往下为正,反之为负。单位为vp/s。
velocity number 获取当前的主方向速度。为xy轴方向速度的平方和的算术平方根。单位为vp/s。

PinchGestureEvent对象说明

元服务API: 从API version 12开始,该接口支持在元服务中使用。

继承于BaseGestureEvent。可将该对象作为onGestureJudgeBegin的event参数来传递。

名称 类型 描述
scale number 缩放比例。
pinchCenterX number 捏合手势中心点相对于当前组件元素原始区域左上角x轴坐标,单位为vp。
pinchCenterY number 捏合手势中心点相对于当前组件元素原始区域左上角y轴坐标,单位为vp。

RotationGestureEvent对象说明

元服务API: 从API version 12开始,该接口支持在元服务中使用。

继承于BaseGestureEvent。可将该对象作为onGestureJudgeBegin的event参数来传递。

名称 类型 描述
angle number 表示旋转角度,单位为deg。说明:角度计算方式:滑动手势被识别到后,连接两根手指之间的线被识别为起始线条,随着手指的滑动,手指之间的线条会发生旋转,根据起始线条两端点和当前线条两端点的坐标,使用反正切函数分别计算其相对于水平方向的夹角,最后arctan2(cy2-cy1,cx2-cx1)-arctan2(y2-y1,x2-x1)为旋转的角度。以起始线条为坐标系,顺时针旋转为0到180度,逆时针旋转为-180到0度。

SwipeGestureEvent对象说明

继承于BaseGestureEvent。可将该对象作为onGestureJudgeBegin的event参数来传递。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

名称 类型 描述
angle number 表示滑动手势的角度,即两根手指间的线段与水平方向的夹角变化的度数,单位为deg。说明:角度计算方式:滑动手势被识别到后,连接两根手指之间的线被识别为起始线条,随着手指的滑动,手指之间的线条会发生旋转,根据起始线条两端点和当前线条两端点的坐标,使用反正切函数分别计算其相对于水平方向的夹角,最后arctan2(cy2-cy1,cx2-cx1)-arctan2(y2-y1,x2-x1)为旋转的角度。以起始线条为坐标系,顺时针旋转为0到180度,逆时针旋转为-180到0度。
speed number 滑动手势速度,即所有手指相对当前组件元素原始区域滑动的平均速度,单位为vp/s。

示例

示例1(自定义手势判定)

该示例通过配置onGestureJudgeBegin实现了对长按、滑动和拖动手势的自定义判定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { promptAction } from '@kit.ArkUI';

// 手势判定 demo
@Entry
@Component
struct GestureJudgeExample {
scroller: Scroller = new Scroller()

build() {
NavDestination() {
Scroll(this.scroller) {
Column({ space: 8 }) {
Text("Drag 上下两层 上层绑定长按,下层绑定拖拽。先长按后平移上半区红色区域只会响应长按,先长按后平移下半区蓝色区域只会响应拖拽")
.width('100%')
.fontSize(20)
.fontColor('0xffdd00')
.backgroundColor(0xeeddaa00)
Stack({ alignContent: Alignment.Center }) {
Column() {
// 模拟上半区和下半区
Stack().width('200vp').height('100vp').backgroundColor(Color.Red)
Stack().width('200vp').height('100vp').backgroundColor(Color.Blue)
}.width('200vp').height('200vp')

// Stack的下半区是绑定了拖动手势的图像区域。
Image($r('sys.media.ohos_app_icon'))
.draggable(true)
.onDragStart(() => {
promptAction.showToast({ message: "Drag 下半区蓝色区域,Image响应" })
})
.width('200vp').height('200vp')
// Stack的上半区是绑定了长按手势的浮动区域。
Stack() {
}
.width('200vp')
.height('200vp')
.hitTestBehavior(HitTestMode.Transparent)
.onGestureJudgeBegin((gestureInfo: GestureInfo, event: BaseGestureEvent) => {
// 确定tag标志是否有值
if (gestureInfo.tag) {
console.log("gestureInfo tag" + gestureInfo.tag.toString())
}
console.log("gestureInfo Type " + gestureInfo.type.toString() + " isSystemGesture " +
gestureInfo.isSystemGesture);
console.log("pressure " + event.pressure + " fingerList.length " + event.fingerList.length
+ " timeStamp " + event.timestamp + " sourceType " + event.source.toString() + " titleX " +
event.tiltX + " titleY " + event.tiltY + " sourcePool " + event.sourceTool.toString());
// 如果是长按类型手势,判断点击的位置是否在上半区
if (gestureInfo.type == GestureControl.GestureType.LONG_PRESS_GESTURE) {
if (event.fingerList.length > 0 && event.fingerList[0].localY < 100) {
return GestureJudgeResult.CONTINUE
} else {
return GestureJudgeResult.REJECT
}
}
return GestureJudgeResult.CONTINUE
})
.gesture(GestureGroup(GestureMode.Parallel,
LongPressGesture()
.onAction((event: GestureEvent) => {
promptAction.showToast({ message: "LongPressGesture 长按上半区 红色区域,红色区域响应" })
})
.tag("tap111")
))

}.width('100%')
}.width('100%')
}
}.width("100%")
.height("100%")
}
}

@Builder
export function GestureJudgeExampleBuilder() {
GestureJudgeExample()
}

img

示例2(自定义区域手势判定)

该示例通过配置onGestureJudgeBegin判定区域决定长按手势和拖拽是否响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { promptAction } from '@kit.ArkUI';

@Entry
@Component
struct GestureJudgeExample2 {
scroller: Scroller = new Scroller()

build() {
NavDestination() {
Scroll(this.scroller) {
Column({ space: 8 }) {
Text("Drag 上下两层 上层绑定长按,下层绑定拖拽。先长按后平移上半区红色区域只会响应长按,先长按后平移下半区蓝色区域只会响应拖拽")
.width('100%')
.fontSize(20)
.fontColor('0xffdd00')
.backgroundColor(0xeeddaa00)
Stack({ alignContent: Alignment.Center }) {
Column() {
// 模拟上半区和下半区
Stack().width('200vp').height('100vp').backgroundColor(Color.Red)
Stack().width('200vp').height('100vp').backgroundColor(Color.Blue)
}.width('200vp').height('200vp')

// Stack的下半区是绑定了拖动手势的图像区域。
Image($r('sys.media.ohos_app_icon'))
.draggable(true)
.onDragStart(() => {
promptAction.showToast({ message: "Drag 下半区蓝色区域,Image响应" })
})
.width('200vp').height('200vp')
// Stack的上半区是绑定了长按手势的浮动区域。
Stack() {
}
.width('200vp')
.height('200vp')
.hitTestBehavior(HitTestMode.Transparent)
.onGestureJudgeBegin((gestureInfo: GestureInfo, event: BaseGestureEvent) => {
// 确定tag标志是否有值
if (gestureInfo.tag) {
console.log("gestureInfo tag" + gestureInfo.tag.toString())
}
console.log("gestureInfo Type " + gestureInfo.type.toString() + " isSystemGesture " +
gestureInfo.isSystemGesture);
console.log("pressure " + event.pressure + " fingerList.length " + event.fingerList.length
+ " timeStamp " + event.timestamp + " sourceType " + event.source.toString() + " titleX " +
event.tiltX + " titleY " + event.tiltY + " sourcePool " + event.sourceTool.toString());
// 如果是长按类型手势,判断点击的位置是否在上半区
if (gestureInfo.type == GestureControl.GestureType.LONG_PRESS_GESTURE) {
if (event.fingerList.length > 0 && event.fingerList[0].localY < 100) {
return GestureJudgeResult.CONTINUE
} else {
return GestureJudgeResult.REJECT
}
}
return GestureJudgeResult.CONTINUE
})
.gesture(GestureGroup(GestureMode.Parallel,
LongPressGesture()
.onAction((event: GestureEvent) => {
promptAction.showToast({ message: "LongPressGesture 长按上半区 红色区域,红色区域响应" })
})
.tag("tap111")
))

}.width('100%')
}.width('100%')
}
}.width("100%")
.height("100%")
}
}

@Builder
export function GestureJudgeExample2Builder() {
GestureJudgeExample2()
}

img

手势拦截增强

为组件提供手势拦截能力。开发者可根据需要,将系统内置手势和比其优先级高的手势做并行化处理,并可以动态控制手势事件的触发。

说明

从API Version 12开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

shouldBuiltInRecognizerParallelWith

shouldBuiltInRecognizerParallelWith(callback: ShouldBuiltInRecognizerParallelWithCallback): T

提供系统内置手势与响应链上其他组件的手势设置并行关系的回调事件。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 参数类型 必填 参数描述
callback ShouldBuiltInRecognizerParallelWithCallback 提供系统内置手势与响应链上其他组件的手势设置并行关系的回调事件,当该组件做触摸碰撞测试时,会触发用户定义的回调来形成手势并行关系。

返回值:

类型 说明
T 返回当前组件。

ShouldBuiltInRecognizerParallelWithCallback

type ShouldBuiltInRecognizerParallelWithCallback = (current: GestureRecognizer, others: Array) => GestureRecognizer

提供系统内置手势与响应链上其他组件的手势设置并行关系的回调事件类型。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
current GestureRecognizer 当前组件的系统内置手势识别器,当前版本只提供内置的PAN_GESTURE类型的手势识别器。
others Array<GestureRecognizer> 响应链上更高优先级的其他组件相同类别的手势识别器。

返回值:

类型 说明
GestureRecognizer 与current识别器绑定并行关系的某个手势识别器。

GestureRecognizer

手势识别器对象。

getTag

getTag(): string

返回当前手势识别器的tag。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
string 当前手势识别器的tag。

getType

getType(): GestureControl.GestureType

返回当前手势识别器的类型。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
GestureControl.GestureType 当前手势识别器的类型。

isBuiltIn

isBuiltIn(): boolean

返回当前手势识别器是否为系统内置手势。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
boolean 当前手势识别器是否为系统内置手势。

setEnabled

setEnabled(isEnabled: boolean): void

设置当前手势识别器的使能状态。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
isEnabled boolean 手势识别器的使能状态。

isEnabled

isEnabled(): boolean

返回当前手势识别器的使能状态。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
boolean 当前手势识别器的使能状态。

getState

getState(): GestureRecognizerState

返回当前手势识别器的状态。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
GestureRecognizerState 当前手势识别器的状态。

getEventTargetInfo

getEventTargetInfo(): EventTargetInfo

返回当前手势识别器对应组件的信息。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
EventTargetInfo 当前手势识别器对应组件的信息。

isValid

isValid(): boolean;

返回当前手势识别器是否有效。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
boolean 当前手势识别器是否有效。当该识别器绑定的组件被析构或者该识别器不在响应链上时返回false。

GestureRecognizerState

定义手势识别器状态。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

名称 描述
READY 0 准备状态。
DETECTING 1 检测状态。
PENDING 2 等待状态。
BLOCKED 3 阻塞状态。
SUCCESSFUL 4 成功状态。
FAILED 5 失败状态。

EventTargetInfo

手势识别器对应组件的信息。

getId

getId(): string

返回当前组件的组件标识。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
string 当前组件的组件标识

ScrollableTargetInfo

手势识别器对应的滚动类容器组件的信息,继承于EventTargetInfo

isBegin

isBegin(): boolean

返回当前滚动类容器组件是否在顶部,如果为Swiper组件且在循环模式下返回false。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
boolean 当前滚动类容器组件是否在顶部。

isEnd

isEnd(): boolean

返回当前滚动类容器组件是否在底部,如果为Swiper组件且在循环模式下返回false。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
boolean 当前滚动类容器组件是否在底部。

PanRecognizer

拖动手势识别器对象,继承于GestureRecognizer

getPanGestureOptions

getPanGestureOptions(): PanGestureOptions

返回当前拖动手势识别器的属性。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

返回值:

类型 说明
PanGestureOptions 当前拖动手势识别器的属性。

onGestureRecognizerJudgeBegin(13+)

onGestureRecognizerJudgeBegin(callback: GestureRecognizerJudgeBeginCallback, exposeInnerGesture: boolean): T

给组件绑定自定义手势识别器判定回调。

新增exposeInnerGesture参数作为是否将回调暴露给ArkUI原生组合组件的内置组件的标识,当该标识置为true时,将回调暴露给ArkUI原生组合组件的内置组件。

对于不需要将回调暴露给ArkUI原生组合组件内置组件的场景,建议采用原有onGestureRecognizerJudgeBegin接口。若要求将回调暴露给ArkUI原生组合组件的内置组件,建议使用该接口并将exposeInnerGesture设置为true。

元服务API: 从API version 13开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 参数类型 必填 参数描述
callback GestureRecognizerJudgeBeginCallback 给组件绑定自定义手势识别器判定回调,当绑定到该组件的手势被接受时,会触发用户定义的回调来获取结果。
exposeInnerGesture boolean 暴露内部手势标识。默认值:false说明:如果是组合组件,此参数设置true,则会在current参数回调出组合组件内部的手势识别器。当前仅支持Tabs,其他组件请不要设置此参数。设置为false时,功能与原接口onGestureRecognizerJudgeBegin相同。

onGestureRecognizerJudgeBegin

onGestureRecognizerJudgeBegin(callback: GestureRecognizerJudgeBeginCallback): T

给组件绑定自定义手势识别器判定回调。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 参数类型 必填 参数描述
callback GestureRecognizerJudgeBeginCallback 给组件绑定自定义手势识别器判定回调,当绑定到该组件的手势被接受时,会触发用户定义的回调来获取结果。

返回值:

类型 说明
T 返回当前组件。

GestureRecognizerJudgeBeginCallback

type GestureRecognizerJudgeBeginCallback = (event: BaseGestureEvent, current: GestureRecognizer, recognizers: Array) => GestureJudgeResult

自定义手势识别器判定回调类型。

元服务API: 从API version 12开始,该接口支持在元服务中使用。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
event BaseGestureEvent 当前基础手势事件信息。
current GestureRecognizer 当前即将要响应的识别器对象。
others Array<GestureRecognizer> 响应链上的其他手势识别器对象。

返回值:

类型 说明
GestureJudgeResult 手势是否裁决成功的判定结果。

示例

示例1(嵌套滚动)

该示例通过shouldBuiltInrecognizerParallelWith和onGestureRecognizerJudgeBegin实现了嵌套滚动的功能。内部组件优先响应滑动手势,当内部组件滑动至顶部或底部时,外部组件能够接替滑动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
@Entry
@Component
struct FatherControlChild {
scroller: Scroller = new Scroller()
scroller2: Scroller = new Scroller()
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
private childRecognizer: GestureRecognizer = new GestureRecognizer()
private currentRecognizer: GestureRecognizer = new GestureRecognizer()
private lastOffset: number = 0

build() {
Stack({ alignContent: Alignment.TopStart }) {
Scroll(this.scroller) { // 外部滚动容器
Column() {
Text("Scroll Area")
.width('90%')
.height(150)
.backgroundColor(0xFFFFFF)
.borderRadius(15)
.fontSize(16)
.textAlign(TextAlign.Center)
.margin({ top: 10 })
Scroll(this.scroller2) { // 内部滚动容器
Column() {
Text("Scroll Area2")
.width('90%')
.height(150)
.backgroundColor(0xFFFFFF)
.borderRadius(15)
.fontSize(16)
.textAlign(TextAlign.Center)
.margin({ top: 10 })
Column() {
ForEach(this.arr, (item: number) => {
Text(item.toString())
.width('90%')
.height(150)
.backgroundColor(0xFFFFFF)
.borderRadius(15)
.fontSize(16)
.textAlign(TextAlign.Center)
.margin({ top: 10 })
}, (item: string) => item)
}.width('100%')
}
}
.id("inner")
.width('100%')
.height(800)
}.width('100%')
}
.id("outer")
.height(600)
.scrollable(ScrollDirection.Vertical) // 滚动方向纵向
.scrollBar(BarState.On) // 滚动条常驻显示
.scrollBarColor(Color.Gray) // 滚动条颜色
.scrollBarWidth(10) // 滚动条宽度
.edgeEffect(EdgeEffect.None)
.shouldBuiltInRecognizerParallelWith((current: GestureRecognizer, others: Array<GestureRecognizer>) => {
for (let i = 0; i < others.length; i++) {
let target = others[i].getEventTargetInfo();
if (target) {
if (target.getId() == "inner" && others[i].isBuiltIn() && others[i].getType() == GestureControl.GestureType.PAN_GESTURE) { // 找到将要组成并行手势的识别器
this.currentRecognizer = current; // 保存当前组件的识别器
this.childRecognizer = others[i]; // 保存将要组成并行手势的识别器
return others[i]; // 返回将要组成并行手势的识别器
}
}
}
return undefined;
})
.onGestureRecognizerJudgeBegin((event: BaseGestureEvent, current: GestureRecognizer, others: Array<GestureRecognizer>) => { // 在识别器即将要成功时,根据当前组件状态,设置识别器使能状态
if (current) {
let target = current.getEventTargetInfo();
if (target) {
if (target.getId() == "outer" && current.isBuiltIn() && current.getType() == GestureControl.GestureType.PAN_GESTURE) {
if (others) {
for (let i = 0; i < others.length; i++) {
let target = others[i].getEventTargetInfo() as ScrollableTargetInfo;
if (target instanceof ScrollableTargetInfo && target.getId() == "inner") { // 找到响应链上对应并行的识别器
let panEvent = event as PanGestureEvent;
if (target.isEnd()) { // 根据当前组件状态以及移动方向动态控制识别器使能状态
if (panEvent && panEvent.offsetY < 0) {
this.childRecognizer.setEnabled(false)
this.currentRecognizer.setEnabled(true)
} else {
this.childRecognizer.setEnabled(true)
this.currentRecognizer.setEnabled(false)
}
} else if (target.isBegin()) {
if (panEvent.offsetY > 0) {
this.childRecognizer.setEnabled(false)
this.currentRecognizer.setEnabled(true)
} else {
this.childRecognizer.setEnabled(true)
this.currentRecognizer.setEnabled(false)
}
} else {
this.childRecognizer.setEnabled(true)
this.currentRecognizer.setEnabled(false)
}
}
}
}
}
}
}
return GestureJudgeResult.CONTINUE;
})
.parallelGesture( // 绑定一个Pan手势作为动态控制器
PanGesture()
.onActionUpdate((event: GestureEvent)=>{
if (this.childRecognizer.getState() != GestureRecognizerState.SUCCESSFUL || this.currentRecognizer.getState() != GestureRecognizerState.SUCCESSFUL) { // 如果识别器状态不是SUCCESSFUL,则不做控制
return;
}
let target = this.childRecognizer.getEventTargetInfo() as ScrollableTargetInfo;
let currentTarget = this.currentRecognizer.getEventTargetInfo() as ScrollableTargetInfo;
if (target instanceof ScrollableTargetInfo && currentTarget instanceof ScrollableTargetInfo) {
if (target.isEnd()) { // 在移动过程中实时根据当前组件状态,控制识别器的开闭状态
if ((event.offsetY - this.lastOffset) < 0) {
this.childRecognizer.setEnabled(false)
if (currentTarget.isEnd()) {
this.currentRecognizer.setEnabled(false)
} else {
this.currentRecognizer.setEnabled(true)
}
} else {
this.childRecognizer.setEnabled(true)
this.currentRecognizer.setEnabled(false)
}
} else if (target.isBegin()) {
if ((event.offsetY - this.lastOffset) > 0) {
this.childRecognizer.setEnabled(false)
if (currentTarget.isBegin()) {
this.currentRecognizer.setEnabled(false)
} else {
this.currentRecognizer.setEnabled(true)
}
} else {
this.childRecognizer.setEnabled(true)
this.currentRecognizer.setEnabled(false)
}
} else {
this.childRecognizer.setEnabled(true)
this.currentRecognizer.setEnabled(false)
}
}
this.lastOffset = event.offsetY
})
)
}.width('100%').height('100%').backgroundColor(0xDCDCDC)
}
}

示例2(嵌套场景下拦截内部容器手势)

本示例通过将参数exposeInnerGesture设置为true,实现了一级Tabs容器在嵌套二级Tabs的场景下,能够屏蔽二级Tabs内置Swiper的滑动手势,从而触发一级Tabs内置Swiper滑动手势的功能。

开发者自行定义变量来记录内层Tabs的索引值,通过该索引值判断当滑动达到内层Tabs的边界处时,触发回调返回屏蔽使外层Tabs产生滑动手势。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// 手势拦截 Demo2
// 本示例通过将参数exposeInnerGesture设置为true,实现了一级Tabs容器在嵌套二级Tabs的场景下,能够屏蔽二级Tabs内置Swiper的滑动手势,从而触发一级Tabs内置Swiper滑动手势的功能。
// 开发者自行定义变量来记录内层Tabs的索引值,通过该索引值判断当滑动达到内层Tabs的边界处时,触发回调返回屏蔽使外层Tabs产生滑动手势。
@Entry
@Component
struct GestureInterceptExample2 {
@State currentIndex: number = 0
@State selectedIndex: number = 0
@State fontColor: string = '#182431'
@State selectedFontColor: string = '#007DFF'
innerSelectedIndex: number = 0 // 记录内层Tabs的索引
controller?: TabsController = new TabsController();
@Builder
tabBuilder(index: number, name: string) {
Column() {
Text(name)
.fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
.fontSize(16)
.fontWeight(this.selectedIndex === index ? 500 : 400)
.lineHeight(22)
.margin({ top: 17, bottom: 7 })
Divider()
.strokeWidth(2)
.color('#007DFF')
.opacity(this.selectedIndex === index ? 1 : 0)
}.width('100%')
}
build() {
NavDestination() {
Column() {
Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
TabContent() {
Column().width('100%').height('100%').backgroundColor(Color.Green)
}.tabBar(this.tabBuilder(0, 'green'))

TabContent() {
Tabs() {
TabContent() {
Column().width('100%').height('100%').backgroundColor(Color.Blue)
}.tabBar(new SubTabBarStyle('blue'))

TabContent() {
Column().width('100%').height('100%').backgroundColor(Color.Pink)
}.tabBar(new SubTabBarStyle('pink'))
}
.onAnimationStart((index: number, targetIndex: number) => {
console.info('ets onGestureRecognizerJudgeBegin child:' + targetIndex)
this.innerSelectedIndex = targetIndex
})
.onGestureRecognizerJudgeBegin((event: BaseGestureEvent, current: GestureRecognizer,
others: Array<GestureRecognizer>): GestureJudgeResult => { // 在识别器即将要成功时,根据当前组件状态,设置识别器使能状态
console.info('ets onGestureRecognizerJudgeBegin child')
if (current) {
let target = current.getEventTargetInfo();
if (target && current.isBuiltIn() && current.getType() == GestureControl.GestureType.PAN_GESTURE) {
console.info('ets onGestureRecognizerJudgeBegin child PAN_GESTURE')
let swiperTaget = target as ScrollableTargetInfo
if (swiperTaget instanceof ScrollableTargetInfo) {
console.info('ets onGestureRecognizerJudgeBegin child PAN_GESTURE isEnd: ' + swiperTaget.isEnd() +
' isBegin: ' + swiperTaget.isBegin())
}
if (swiperTaget instanceof ScrollableTargetInfo &&
((swiperTaget.isEnd() || this.innerSelectedIndex ===
1) || // 此处判断swiperTaget.isEnd()或innerSelectedIndex === 内层Tabs的总数 - 1,表明内层Tabs滑动到尽头
(swiperTaget.isBegin() || this.innerSelectedIndex ===
0))) { // 此处判断swiperTaget.isBegin()或innerSelectedIndex === 0,表明内层Tabs滑动到开头
let panEvent = event as PanGestureEvent;
console.log('pan direction:' + panEvent.offsetX + ' begin:' + swiperTaget.isBegin() + ' end:' +
swiperTaget.isEnd() + ' index:' + this.innerSelectedIndex)
if (panEvent && panEvent.offsetX < 0 && (swiperTaget.isEnd() || this.innerSelectedIndex === 1)) {
console.info('ets onGestureRecognizerJudgeBegin child reject end')
return GestureJudgeResult.REJECT;
}
if (panEvent && panEvent.offsetX > 0 && (swiperTaget.isBegin() || this.innerSelectedIndex === 0)) {
console.info('ets onGestureRecognizerJudgeBegin child reject begin')
return GestureJudgeResult.REJECT;
}
}
}
}
return GestureJudgeResult.CONTINUE;
})
}.tabBar(this.tabBuilder(1, 'blue and pink'))

TabContent() {
Column().width('100%').height('100%').backgroundColor(Color.Brown)
}.tabBar(this.tabBuilder(2, 'brown'))
}
.onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
// 切换动画开始时触发该回调。目标页签显示下划线。
this.selectedIndex = targetIndex
})
}
}.width('100%')
.height('100%')
}
}

@Builder
export function GestureInterceptExample2Builder() {
GestureInterceptExample2()
}

img

四、触摸事件原理

Harmony触摸事件捕获和事件冒泡

img

事件处理原理

  • 事件监听: 在 ArkUI 中,事件监听是通过在组件上指定事件属性来实现的。例如,你可以为按钮组件添加一个 onClick 属性来监听点击事件。
  • 事件对象: 当事件被触发时,一个事件对象会被传递给事件处理函数。这个对象包含了事件的详细信息,如事件类型、触发事件的元素、事件坐标等。
  • 事件传播: 事件传播包括捕获阶段和冒泡阶段。在捕获阶段,事件从根元素向下传播到目标元素;在冒泡阶段,事件从目标元素向上传播回根元素。
  • 事件处理函数: 事件处理函数可以是内联函数,也可以是组件方法中的一个函数。在函数内部,你可以执行任何逻辑来响应事件。

暂时无法在飞书文档外展示此内容

iOS触摸事件捕获

img

img

H5 触摸事件捕获和事件冒泡

DOM 事件标准描述了事件传播的 3 个阶段:

  1. 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
  2. 目标阶段(Target phase)—— 事件到达目标元素。
  3. 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。

img

Android触摸事件分发

img

img

五、参考

HarmonyOS NEXT应用开发案例——阻塞事件冒泡

HarmonyOS 鸿蒙Next 组件的触摸事件分发机制到底是怎么样的

HarmonyOS ArkUI 框架的实现原理和落地实践

深入理解DOM事件流:事件捕获与事件冒泡

冒泡和捕获

最近的文章

Rust - 基于 FFI 的移动端跨平台 SDK 的探索和实践

为什么要跨平台 减少人力成本,减少开发时间。 抹平多端在逻辑细节的实现差异,提高代码一致性,保证工程质量。 多个平台共享一套代码,后期产品维护简单。 目前常见的跨平台方案C++很多公司的跨平台移动基础库基本都有 C++ 的影子,如微信,腾讯会议,还有早期的 Dropbox,知名的开源库如微信 …

, , 开始阅读
更早的文章

iOS 端基于 NLP/CoreML + Vision 实现「图像文字识别&提取」

前言 阅读本文内容前,你可能需要了解的基础知识「端智能」基于自然语言处理 (NLP) 的光学字符识别 (OCR) 在最近的技术分享中,我们已经知道了实现「图像文字识别&amp;提取」这个功能所需的基本技术方案和原理 ,这解决了我们实现这一功能当中 Why 和 What 的问题。但光知道 Why …

, , , , , 开始阅读
comments powered by Disqus