# 3.11:手势设置
笔者在第 2 节公共事件类属性中讲述组件的公共事件属性,比如点击事件、触摸事件等,这些事件默认遵循冒泡机制,ArkUI开发框架提供了 3 种手势识别方法供开发者控制事件的冒泡机制,本节笔者简单介绍一下这三种手势识别器的用法。
# 3.11.1:手势类属性定义介绍
declare class CommonMethod<T> {
gesture(gesture: GestureType, mask?: GestureMask): T;
priorityGesture(gesture: GestureType, mask?: GestureMask): T;
parallelGesture(gesture: GestureType, mask?: GestureMask): T;
}
declare type GestureType = TapGestureInterface // 点击手势,支持单次点击、多次点击识别。
| LongPressGestureInterface // 长按手势。
| PanGestureInterface // 平移手势。
| PinchGestureInterface // 捏合手势。
| SwipeGestureInterface // 擦除手势。
| RotationGestureInterface // 旋转手势。
| GestureGroupInterface; // 手势识别组,多种手势组合为复合手势,支持连续识别、并行识别和互斥识别。
declare enum GestureMask {
Normal, // 不屏蔽子组件的手势,按照默认手势识别顺序进行识别。
IgnoreInternal, // 屏蔽子组件的手势,仅当前容器的手势进行识别。注意:子组件上系统内置的手势不会被屏蔽,如子组件为List组件时,内置的滑动手势仍然会触发。
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CommonMethod
提供了 gesture()
、 priorityGesture()
和 parallelGesture()
3 个绑定手势识别器的方法, 它们区别如下:
- gesture:给当前组件绑定手势识别器,子组件优于父组件识别手势。
- priorityGesture:绑定优先识别手势。默认情况下,子组件优先于父组件识别手势,当父组件配置此方法时,父组件优先于子组件进行识别。
- parallelGesture:绑定可与子组件手势同时触发的手势。手势事件为非冒泡事件。父组件设置此方法时,父子组件相同的手势事件都可以触发,实现类似冒泡效果。
以上 3 个方法的参数都是一致的,参数 gesture
表示手势识别器, GestureType
提供了以下 7 种手势识别器,
- TapGesture:点击手势,支持单次点击、多次点击识别。
- LongPressGesture:长按手势。
- PanGesture:平移手势。
- PinchGesture:捏合手势。
- RotationGesture:旋转手势。
- SwipeGesture:擦除手势。
- GestureGroup:手势识别组,多种手势组合为复合手势,支持连续识别、并行识别和互斥识别。
mask
表示设置父子组件对的手势识别顺序, GestureMask
提供了以下 2 种识别顺序:
- Normal(默认值):不屏蔽子组件的手势,按照默认手势识别顺序进行识别。
- IgnoreInternal:屏蔽子组件的手势,仅当前父组件的手势进行识别。注意:子组件上系统内置的手势不会被屏蔽,如子组件为
List
组件时,内置的滑动手势仍然会触发。
接下来笔者分别介绍一下以上各种手势识别器的用法。
# 3.11.2:点击手势TapGesture
interface TapGestureInterface {
(value?: { count?: number; fingers?: number }): TapGestureInterface;
onAction(event: (event?: GestureEvent) => void): TapGestureInterface;
}
2
3
4
创建点击手势识别器时可以配置相关参数, count
表示识别次数, fingers
表示手指数量, onAction
表示点击手势识别的事件回调。
gesture:给当前组件绑定手势识别器,子组件优于父组件识别手势。
@Entry @Component struct GestureTest { @State info: string = "Gesture..."; build() { Column({space: 10}) { Text(this.info) .width("100%") .fontSize(22) .textAlign(TextAlign.Center) Stack() { Text("") .width(200) .height(100) .fontSize(20) .id("child") .backgroundColor("#bbccaa") .gesture( // 子组件设置手势识别 TapGesture({ count: 1, fingers: 1 }).onAction((event) => { this.info = "TapGesture in children"; console.log("TapGesture in children") } ), GestureMask.Normal) // 子组件事件类型为Normal .backgroundColor("#bbaacc") } .width("100%") .height(120) .id("parent") .gesture( // 父组件设置手势识别 TapGesture({ count: 1, fingers: 1 }).onAction((event) => { this.info = "TapGesture in parent"; console.log("TapGesture in parent") } ), GestureMask.IgnoreInternal) // 父组件事件类型为IgnoreInternal .backgroundColor("#aabbcc") } .width('100%') .height('100%') .padding(10) } }
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样例运行结果如下图所示:
如上所示,
id
为child
和parent
的父子组件同时通过gesture()
方法设置了手势识别器,事件按照正常派发流程派发给子组件。📢:笔者在测试
gesture()
方法时,无论父组件的识别顺序GestureMask
设置成Normal
还是IgnoreInternal
,结果均不起作用。priorityGesture:绑定优先识别手势,父组件优先于子组件识别手势。
@Entry @Component struct GestureTest { @State info: string = "Gesture..."; build() { Column({space: 10}) { Text(this.info) .width("100%") .fontSize(22) .textAlign(TextAlign.Center) Stack() { Text("") .width(200) .height(100) .fontSize(20) .id("child") .backgroundColor("#bbccaa") .gesture( // 子组件设置手势识别 TapGesture({ count: 1, fingers: 1 }).onAction((event) => { this.info = this.info + " | TapGesture in children"; console.log("TapGesture in children") } ), GestureMask.Normal) // 子组件事件类型为Normal .backgroundColor("#bbaacc") } .width("100%") .height(120) .id("parent") .priorityGesture( // 父组件设置手势识别 TapGesture({ count: 1, fingers: 1 }).onAction((event) => { this.info = "TapGesture in parent"; console.log("TapGesture in parent") } ), GestureMask.IgnoreInternal) // 父组件事件类型为IgnoreInternal .backgroundColor("#aabbcc") } .width('100%') .height('100%') .padding(10) } }
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样例运行结果如下图所示:
如上所示,
id
为parent
的父组件通过priorityGesture()
方法设置了手势识别器,id
为child
的子组件通过gesture()
方法设置了手势识别器,事件优先派发给了父组件而不会派发给子组件。📢:笔者在测试
gesture()
方法时,无论父组件的识别顺序GestureMask
设置成Normal
还是IgnoreInternal
,结果均不起作用。parallelGesture:绑定可与子组件手势同时触发的手势。
@Entry @Component struct GestureTest { @State info: string = "Gesture..."; build() { Column({space: 10}) { Text(this.info) .width("100%") .fontSize(22) .textAlign(TextAlign.Center) Stack() { Text("") .width(200) .height(100) .fontSize(20) .id("child") .backgroundColor("#bbccaa") .gesture( // 子组件设置手势识别 TapGesture({ count: 1, fingers: 1 }).onAction((event) => { this.info = this.info + " | in children"; console.log("TapGesture in children") } ), GestureMask.Normal) // 子组件事件类型为Normal .backgroundColor("#bbaacc") } .width("100%") .height(120) .id("parent") .parallelGesture( // 父组件设置手势识别 TapGesture({ count: 1, fingers: 1 }).onAction((event) => { this.info = "TapGesture in parent"; console.log("TapGesture in parent") } ), GestureMask.IgnoreInternal) // 父组件事件类型为IgnoreInternal .backgroundColor("#aabbcc") } .width('100%') .height('100%') .padding(10) } }
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样例运行结果如下图所示:
如上所示,
id
为parent
的父组件通过parallelGesture()
方法设置了手势识别器,id
为child
的子组件通过gesture()
方法设置了手势识别器,事件同时派发给了父组件和子组件。📢:笔者在测试
gesture()
方法时,无论父组件的识别顺序GestureMask
设置成Normal
还是IgnoreInternal
,结果均不起作用。
# 3.11.3:长按手势LongPressGesture
interface LongPressGestureInterface {
(value?: { fingers?: number; repeat?: boolean; duration?: number }): LongPressGestureInterface;
onAction(event: (event?: GestureEvent) => void): LongPressGestureInterface;
onActionEnd(event: (event?: GestureEvent) => void): LongPressGestureInterface;
onActionCancel(event: () => void): LongPressGestureInterface;
}
2
3
4
5
6
创建长按手势识别器时可以配置相关参数, fingers
表示手指数量,repeat表示重复识别,duration表示长按时间, onAction
表示长按手势识别的事件回调。onActionEnd表示长按结束时的回调,onActionCancel表示长按取消的回调。
gesture:给当前组件绑定手势识别器,子组件优于父组件识别手势。
@Entry @Component struct GestureTest { @State info: string = "Gesture..."; build() { Column({space: 10}) { Text(this.info) .width("100%") .fontSize(22) .textAlign(TextAlign.Center) Stack() { Text("") .width(200) .height(100) .fontSize(20) .id("child") .backgroundColor("#bbaacc") .gesture( // 子组件设置手势识别 LongPressGesture({ duration: 800, // 长按800毫秒 repeat: false, // 不重复识别 fingers: 1 // 单个手指 }) .onAction(() => { this.info = this.info + " | child:action"; }) .onActionEnd(() => { this.info = this.info + ", end"; }) .onActionCancel(() => { this.info = this.info + ", cancel"; }) ) } .width("100%") .height(120) .id("parent") .backgroundColor("#aabbcc") .gesture( // 子组件设置手势识别 LongPressGesture({ duration: 800, // 长按800毫秒 repeat: false, // 不重复识别 fingers: 1 // 单个手指 }) .onAction(() => { this.info = "parent:action"; }) .onActionEnd(() => { this.info = this.info + ", end"; }) .onActionCancel(() => { this.info = this.info + ", cancel"; }), GestureMask.IgnoreInternal) } .width('100%') .height('100%') .padding(10) } }
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样例运行结果如下图所示:
如上所示,
id
为child
和parent
的父子组件同时通过gesture()
方法设置了手势识别器,事件按照正常派发流程派发给子组件。📢:笔者在测试
gesture()
方法时,无论父组件的识别顺序GestureMask
设置成Normal
还是IgnoreInternal
,结果均不起作用。priorityGesture:绑定优先识别手势,父组件优先于子组件识别手势。
@Entry @Component struct GestureTest { @State info: string = "Gesture..."; build() { Column({space: 10}) { Text(this.info) .width("100%") .fontSize(22) .textAlign(TextAlign.Center) Stack() { Text("") .width(200) .height(100) .fontSize(20) .id("child") .backgroundColor("#bbaacc") .gesture( // 子组件设置手势识别 LongPressGesture({ duration: 800, // 长按800毫秒 repeat: false, // 不重复识别 fingers: 1 // 单个手指 }) .onAction(() => { this.info = this.info + " | child:action"; }) .onActionEnd(() => { this.info = this.info + ", end"; }) .onActionCancel(() => { this.info = this.info + ", cancel"; }) ) } .width("100%") .height(120) .id("parent") .backgroundColor("#aabbcc") .priorityGesture( // 父组件设置手势识别 LongPressGesture({ duration: 800, // 长按800毫秒 repeat: false, // 不重复识别 fingers: 1 // 单个手指 }) .onAction(() => { this.info = "parent:action"; }) .onActionEnd(() => { this.info = this.info + ", end"; }) .onActionCancel(() => { this.info = this.info + ", cancel"; }), GestureMask.IgnoreInternal) } .width('100%') .height('100%') .padding(10) } }
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样例运行结果如下图所示:
如上所示,
id
为parent
的父组件通过priorityGesture()
方法设置了手势识别器,id
为child
的子组件通过gesture()
方法设置了手势识别器,事件优先派发给了父组件而不会派发给子组件。📢:笔者在测试
gesture()
方法时,无论父组件的识别顺序GestureMask
设置成Normal
还是IgnoreInternal
,结果均不起作用。parallelGesture:绑定可与子组件手势同时触发的手势。
@Entry @Component struct GestureTest { @State info: string = "Gesture..."; build() { Column({space: 10}) { Text(this.info) .width("100%") .fontSize(22) .textAlign(TextAlign.Center) Stack() { Text("") .width(200) .height(100) .fontSize(20) .id("child") .backgroundColor("#bbaacc") .gesture( // 子组件设置手势识别 LongPressGesture({ duration: 800, // 长按800毫秒 repeat: false, // 不重复识别 fingers: 1 // 单个手指 }) .onAction(() => { this.info = this.info + " | c:action"; }) .onActionEnd(() => { this.info = this.info + ", cend"; }) .onActionCancel(() => { this.info = this.info + ", ccancel"; }) ) } .width("100%") .height(120) .id("parent") .backgroundColor("#aabbcc") .parallelGesture( // 父组件设置手势识别 LongPressGesture({ duration: 800, // 长按800毫秒 repeat: false, // 不重复识别 fingers: 1 // 单个手指 }) .onAction(() => { this.info = "p:action"; }) .onActionEnd(() => { this.info = this.info + ", pend"; }) .onActionCancel(() => { this.info = this.info + ", pcancel"; }), GestureMask.IgnoreInternal ) } .width('100%') .height('100%') .padding(10) } }
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样例运行结果如下图所示:
如上所示,
id
为parent
的父组件通过parallelGesture()
方法设置了手势识别器,id
为child
的子组件通过gesture()
方法设置了手势识别器,事件同时派发给了父组件和子组件。📢:笔者在测试
gesture()
方法时,无论父组件的识别顺序GestureMask
设置成Normal
还是IgnoreInternal
,结果均不起作用。
# 3.11.4:平移手势PanGesture
interface PanGestureInterface {
(value?: { fingers?: number; direction?: PanDirection; distance?: number } | PanGestureOptions): PanGestureInterface;
onActionStart(event: (event?: GestureEvent) => void): PanGestureInterface;
onActionUpdate(event: (event?: GestureEvent) => void): PanGestureInterface;
onActionEnd(event: (event?: GestureEvent) => void): PanGestureInterface;
onActionCancel(event: () => void): PanGestureInterface;
}
2
3
4
5
6
7
创建平移手势识别器时可以配置相关参数, fingers
表示手指数量, direction
表示平移方向, distance
表示平移距离, onActionXXX
表示平移时的事件回调。
@Entry @Component struct GestureTest {
@State info: string = "Gesture...";
build() {
Column({space: 10}) {
Text(this.info)
.width("100%")
.fontSize(22)
.textAlign(TextAlign.Center)
Stack() {
Text("")
.width(200)
.height(100)
.fontSize(20)
.id("child")
.backgroundColor("#bbaacc")
.gesture( // 子组件设置手势识别
PanGesture({
fingers: 1, // 单个手指
direction: PanDirection.Horizontal, // 水平方向移动
distance: 20 // 平移距离
})
.onActionStart(() => {
this.info = this.info + " | cs";
})
.onActionUpdate(() => {
this.info = this.info + ", cu";
})
.onActionEnd(() => {
this.info = this.info + ", ce";
})
.onActionCancel(() => {
this.info = this.info + ", cc";
})
)
}
.width("100%")
.height(120)
.id("parent")
.backgroundColor("#aabbcc")
.gesture( // 父组件设置手势识别
PanGesture({
fingers: 1, // 单个手指
direction: PanDirection.Horizontal, // 水平方向移动
distance: 20 // 平移距离
})
.onActionStart(() => {
this.info = this.info + " | cs";
})
.onActionUpdate(() => {
this.info = this.info + ", cu";
})
.onActionEnd(() => {
this.info = this.info + ", ce";
})
.onActionCancel(() => {
this.info = this.info + ", cc";
}),
GestureMask.IgnoreInternal
)
}
.width('100%')
.height('100%')
.padding(10)
}
}
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
# 3.11.5:捏合手势PinchGesture
interface PinchGestureInterface {
(value?: { fingers?: number; distance?: number }): PinchGestureInterface;
onActionStart(event: (event?: GestureEvent) => void): PinchGestureInterface;
onActionUpdate(event: (event?: GestureEvent) => void): PinchGestureInterface;
onActionEnd(event: (event?: GestureEvent) => void): PinchGestureInterface;
onActionCancel(event: () => void): PinchGestureInterface;
}
2
3
4
5
6
7
创建捏合手势识别器时可以配置相关参数, fingers
表示手指数量, distance
表示平移距离, onActionXXX
表示平移时的事件回调。
@Entry @Component struct GestureTest {
@State info: string = "Gesture...";
build() {
Column({space: 10}) {
Text(this.info)
.width("100%")
.fontSize(22)
.textAlign(TextAlign.Center)
Stack() {
Text("")
.width(200)
.height(100)
.fontSize(20)
.id("child")
.backgroundColor("#bbaacc")
.gesture( // 子组件设置手势识别
PinchGesture({
fingers: 1, // 2个手指
distance: 20 // 捏合距离
})
.onActionStart(() => {
this.info = this.info + " | cs";
})
.onActionUpdate(() => {
this.info = this.info + ", cu";
})
.onActionEnd(() => {
this.info = this.info + ", ce";
})
.onActionCancel(() => {
this.info = this.info + ", cc";
})
)
}
.width("100%")
.height(120)
.id("parent")
.backgroundColor("#aabbcc")
}
.width('100%')
.height('100%')
.padding(10)
}
}
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
# 3.11.6:旋转手势RotationGesture
interface RotationGestureInterface {
(value?: { fingers?: number; angle?: number }): RotationGestureInterface;
onActionStart(event: (event?: GestureEvent) => void): RotationGestureInterface;
onActionUpdate(event: (event?: GestureEvent) => void): RotationGestureInterface;
onActionEnd(event: (event?: GestureEvent) => void): RotationGestureInterface;
onActionCancel(event: () => void): RotationGestureInterface;
}
2
3
4
5
6
7
创建旋转手势识别器时可以配置相关参数, fingers
表示手指数量, angle
表示旋转角度, onActionXXX
表示平移时的事件回调。
@Entry @Component struct GestureTest {
@State info: string = "Gesture...";
build() {
Column({space: 10}) {
Text(this.info)
.width("100%")
.fontSize(22)
.textAlign(TextAlign.Center)
Stack() {
Text("")
.width(200)
.height(100)
.fontSize(20)
.id("child")
.backgroundColor("#bbaacc")
.gesture( // 子组件设置手势识别
RotationGesture({
fingers: 2, // 2个手指
angle: 20 // 旋转角度
})
.onActionStart(() => {
this.info = this.info + " | cs";
})
.onActionUpdate(() => {
this.info = this.info + ", cu";
})
.onActionEnd(() => {
this.info = this.info + ", ce";
})
.onActionCancel(() => {
this.info = this.info + ", cc";
})
)
}
.width("100%")
.height(120)
.id("parent")
.backgroundColor("#aabbcc")
}
.width('100%')
.height('100%')
.padding(10)
}
}
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