• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 手势拦截增强
2
3为组件提供手势拦截能力。开发者可根据需要,将系统内置手势和比其优先级高的手势做并行化处理,并可以动态控制手势事件的触发。
4
5>  **说明:**
6>
7>  从API Version 12开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
8
9## shouldBuiltInRecognizerParallelWith
10
11shouldBuiltInRecognizerParallelWith(callback: ShouldBuiltInRecognizerParallelWithCallback): T
12
13提供系统内置手势与响应链上其他组件的手势设置并行关系的回调事件。
14
15**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
16
17**系统能力:** SystemCapability.ArkUI.ArkUI.Full
18
19**参数:**
20| 参数名        | 参数类型                    | 必填  | 参数描述                          |
21| ---------- | -------------------------- | ------- | ----------------------------- |
22| callback      | [ShouldBuiltInRecognizerParallelWithCallback](#shouldbuiltinrecognizerparallelwithcallback) | 是   |  提供系统内置手势与响应链上其他组件的手势设置并行关系的回调事件,当该组件做触摸碰撞测试时,会触发用户定义的回调来形成手势并行关系。 |
23
24**返回值:**
25
26| 类型 | 说明 |
27| -------- | -------- |
28| T | 返回当前组件。 |
29
30## ShouldBuiltInRecognizerParallelWithCallback
31
32type ShouldBuiltInRecognizerParallelWithCallback = (current: GestureRecognizer, others: Array\<GestureRecognizer\>) => GestureRecognizer
33
34提供系统内置手势与响应链上其他组件的手势设置并行关系的回调事件类型。
35
36**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
37
38**系统能力:** SystemCapability.ArkUI.ArkUI.Full
39
40**参数:**
41
42| 参数名   | 类型                      | 必填 | 说明                                                         |
43| -------- | ------------------------- | ---- | ------------------------------------------------------------ |
44| current | [GestureRecognizer](#gesturerecognizer) | 是   | 当前组件的系统内置手势识别器,当前版本只提供内置的[PAN_GESTURE](ts-gesture-customize-judge.md#gesturejudgeresult11)类型的手势识别器。 |
45| others | Array\<[GestureRecognizer](#gesturerecognizer)\> | 是   | 响应链上更高优先级的其他组件相同类别的手势识别器。 |
46
47**返回值:**
48
49| 类型     | 说明        |
50| ------ | --------- |
51| [GestureRecognizer](#gesturerecognizer) | 与current识别器绑定并行关系的某个手势识别器。 |
52
53## GestureRecognizer
54
55手势识别器对象。
56
57### getTag
58
59getTag(): string
60
61返回当前手势识别器的tag。
62
63**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
64
65**系统能力:** SystemCapability.ArkUI.ArkUI.Full
66
67**返回值:**
68
69| 类型     | 说明        |
70| ------ | --------- |
71| string | 当前手势识别器的tag。 |
72
73### getType
74
75getType(): GestureControl.GestureType
76
77返回当前手势识别器的类型。
78
79**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
80
81**系统能力:** SystemCapability.ArkUI.ArkUI.Full
82
83**返回值:**
84
85| 类型     | 说明        |
86| ------ | --------- |
87| [GestureControl.GestureType](ts-gesture-customize-judge.md#gesturetype11) | 当前手势识别器的类型。 |
88
89### isBuiltIn
90
91isBuiltIn(): boolean
92
93返回当前手势识别器是否为系统内置手势。
94
95**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
96
97**系统能力:** SystemCapability.ArkUI.ArkUI.Full
98
99**返回值:**
100
101| 类型     | 说明        |
102| ------ | --------- |
103| boolean | 当前手势识别器是否为系统内置手势。 |
104
105### setEnabled
106
107setEnabled(isEnabled: boolean): void
108
109设置当前手势识别器的使能状态。
110
111**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
112
113**系统能力:** SystemCapability.ArkUI.ArkUI.Full
114
115**参数:**
116
117| 参数名     | 类型                           | 必填   | 说明  |
118| ------- | ---------------------------------- | ---- | ----- |
119| isEnabled   | boolean         | 是    | 手势识别器的使能状态。 |
120
121### isEnabled
122
123isEnabled(): boolean
124
125返回当前手势识别器的使能状态。
126
127**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
128
129**系统能力:** SystemCapability.ArkUI.ArkUI.Full
130
131**返回值:**
132
133| 类型     | 说明        |
134| ------ | --------- |
135| boolean | 当前手势识别器的使能状态。 |
136
137### getState
138
139getState(): GestureRecognizerState
140
141返回当前手势识别器的状态。
142
143**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
144
145**系统能力:** SystemCapability.ArkUI.ArkUI.Full
146
147**返回值:**
148
149| 类型     | 说明        |
150| ------ | --------- |
151| [GestureRecognizerState](#gesturerecognizerstate) | 当前手势识别器的状态。 |
152
153### getEventTargetInfo
154
155getEventTargetInfo(): EventTargetInfo
156
157返回当前手势识别器对应组件的信息。
158
159**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
160
161**系统能力:** SystemCapability.ArkUI.ArkUI.Full
162
163**返回值:**
164
165| 类型     | 说明        |
166| ------ | --------- |
167| [EventTargetInfo](#eventtargetinfo) | 当前手势识别器对应组件的信息。 |
168
169### isValid
170
171isValid(): boolean;
172
173返回当前手势识别器是否有效。
174
175**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
176
177**系统能力:** SystemCapability.ArkUI.ArkUI.Full
178
179**返回值:**
180
181| 类型     | 说明        |
182| ------ | --------- |
183| boolean | 当前手势识别器是否有效。当该识别器绑定的组件被析构或者该识别器不在响应链上时返回false。 |
184
185## GestureRecognizerState
186
187定义手势识别器状态。
188
189**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
190
191**系统能力:** SystemCapability.ArkUI.ArkUI.Full
192
193| 名称    | 值   | 描述                               |
194| ------- | ---- | ---------------------------------- |
195| READY | 0    | 准备状态。 |
196| DETECTING    | 1    | 检测状态。 |
197| PENDING    | 2    | 等待状态。 |
198| BLOCKED    | 3    | 阻塞状态。 |
199| SUCCESSFUL    | 4    | 成功状态。 |
200| FAILED    | 5    | 失败状态。 |
201
202## EventTargetInfo
203
204手势识别器对应组件的信息。
205
206### getId
207
208getId(): string
209
210返回当前组件的组件标识。
211
212**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
213
214**系统能力:** SystemCapability.ArkUI.ArkUI.Full
215
216**返回值:**
217
218| 类型     | 说明        |
219| ------ | --------- |
220| string | 当前组件的[组件标识](./ts-universal-attributes-component-id.md#id)。 |
221
222## ScrollableTargetInfo
223
224手势识别器对应的滚动类容器组件的信息,继承于[EventTargetInfo](#eventtargetinfo)。
225
226### isBegin
227
228isBegin(): boolean
229
230返回当前滚动类容器组件是否在顶部,如果为Swiper组件且在循环模式下返回false。
231
232**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
233
234**系统能力:** SystemCapability.ArkUI.ArkUI.Full
235
236**返回值:**
237
238| 类型     | 说明        |
239| ------ | --------- |
240| boolean | 当前滚动类容器组件是否在顶部。 |
241
242### isEnd
243
244isEnd(): boolean
245
246返回当前滚动类容器组件是否在底部,如果为Swiper组件且在循环模式下返回false。
247
248**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
249
250**系统能力:** SystemCapability.ArkUI.ArkUI.Full
251
252**返回值:**
253
254| 类型     | 说明        |
255| ------ | --------- |
256| boolean | 当前滚动类容器组件是否在底部。 |
257
258## PanRecognizer
259
260拖动手势识别器对象,继承于[GestureRecognizer](#gesturerecognizer)。
261
262### getPanGestureOptions
263
264getPanGestureOptions(): PanGestureOptions
265
266返回当前拖动手势识别器的属性。
267
268**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
269
270**系统能力:** SystemCapability.ArkUI.ArkUI.Full
271
272**返回值:**
273
274| 类型     | 说明        |
275| ------ | --------- |
276| [PanGestureOptions](./ts-basic-gestures-pangesture.md#pangestureoptions) | 当前拖动手势识别器的属性。 |
277
278## onGestureRecognizerJudgeBegin<sup>13+</sup>
279
280onGestureRecognizerJudgeBegin(callback: GestureRecognizerJudgeBeginCallback, exposeInnerGesture: boolean): T
281
282给组件绑定自定义手势识别器判定回调。
283
284新增exposeInnerGesture参数作为是否将回调暴露给ArkUI原生组合组件的内置组件的标识,当该标识置为true时,将回调暴露给ArkUI原生组合组件的内置组件。<br>
285对于不需要将回调暴露给ArkUI原生组合组件内置组件的场景,建议采用原有[onGestureRecognizerJudgeBegin](#ongesturerecognizerjudgebegin)接口。若要求将回调暴露给ArkUI原生组合组件的内置组件,建议使用该接口并将exposeInnerGesture设置为true。
286
287**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。
288
289**系统能力:** SystemCapability.ArkUI.ArkUI.Full
290
291**参数:**
292| 参数名        | 参数类型                    | 必填  | 参数描述                          |
293| ---------- | -------------------------- | ------- | ----------------------------- |
294| callback      | [GestureRecognizerJudgeBeginCallback](#gesturerecognizerjudgebegincallback) | 是     |  给组件绑定自定义手势识别器判定回调,当绑定到该组件的手势被接受时,会触发用户定义的回调来获取结果。 |
295| exposeInnerGesture   | boolean         | 是    | 暴露内部手势标识。<br/>默认值:false<br/>**说明:**<br/>如果是组合组件,此参数设置true,则会在current参数回调出组合组件内部的手势识别器。<br>当前仅支持[Tabs](ts-container-tabs.md),其他组件请不要设置此参数。<br/>设置为false时,功能与原接口[onGestureRecognizerJudgeBegin](#ongesturerecognizerjudgebegin)相同。 |
296
297## onGestureRecognizerJudgeBegin
298
299onGestureRecognizerJudgeBegin(callback: GestureRecognizerJudgeBeginCallback): T
300
301给组件绑定自定义手势识别器判定回调。
302
303**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
304
305**系统能力:** SystemCapability.ArkUI.ArkUI.Full
306
307**参数:**
308| 参数名        | 参数类型                    | 必填  | 参数描述                          |
309| ---------- | -------------------------- | ------- | ----------------------------- |
310| callback      | [GestureRecognizerJudgeBeginCallback](#gesturerecognizerjudgebegincallback) | 是     |  给组件绑定自定义手势识别器判定回调,当绑定到该组件的手势被接受时,会触发用户定义的回调来获取结果。 |
311
312**返回值:**
313
314| 类型 | 说明 |
315| -------- | -------- |
316| T | 返回当前组件。 |
317
318## GestureRecognizerJudgeBeginCallback
319
320type GestureRecognizerJudgeBeginCallback = (event: BaseGestureEvent, current: GestureRecognizer, recognizers: Array\<GestureRecognizer\>) => GestureJudgeResult
321
322自定义手势识别器判定回调类型。
323
324**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
325
326**系统能力:** SystemCapability.ArkUI.ArkUI.Full
327
328**参数:**
329
330| 参数名   | 类型                      | 必填 | 说明                                                         |
331| -------- | ------------------------- | ---- | ------------------------------------------------------------ |
332| event | [BaseGestureEvent](./ts-gesture-customize-judge.md#basegestureevent对象说明) | 是   | 当前基础手势事件信息。 |
333| current | [GestureRecognizer](#gesturerecognizer) | 是   | 当前即将要响应的识别器对象。 |
334| others | Array\<[GestureRecognizer](#gesturerecognizer)\> | 是   | 响应链上的其他手势识别器对象。 |
335
336**返回值:**
337
338| 类型     | 说明        |
339| ------ | --------- |
340| [GestureJudgeResult](ts-gesture-customize-judge.md#gesturejudgeresult11) | 手势是否裁决成功的判定结果。 |
341
342## 示例
343
344### 示例1
345
346```ts
347// xxx.ets
348@Entry
349@Component
350struct FatherControlChild {
351  scroller: Scroller = new Scroller()
352  scroller2: Scroller = new Scroller()
353  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
354  private childRecognizer: GestureRecognizer = new GestureRecognizer()
355  private currentRecognizer: GestureRecognizer = new GestureRecognizer()
356  private lastOffset: number = 0
357
358  build() {
359    Stack({ alignContent: Alignment.TopStart }) {
360      Scroll(this.scroller) { // 外部滚动容器
361        Column() {
362          Text("Scroll Area")
363            .width('90%')
364            .height(150)
365            .backgroundColor(0xFFFFFF)
366            .borderRadius(15)
367            .fontSize(16)
368            .textAlign(TextAlign.Center)
369            .margin({ top: 10 })
370          Scroll(this.scroller2) { // 内部滚动容器
371            Column() {
372              Text("Scroll Area2")
373                .width('90%')
374                .height(150)
375                .backgroundColor(0xFFFFFF)
376                .borderRadius(15)
377                .fontSize(16)
378                .textAlign(TextAlign.Center)
379                .margin({ top: 10 })
380              Column() {
381                ForEach(this.arr, (item: number) => {
382                  Text(item.toString())
383                    .width('90%')
384                    .height(150)
385                    .backgroundColor(0xFFFFFF)
386                    .borderRadius(15)
387                    .fontSize(16)
388                    .textAlign(TextAlign.Center)
389                    .margin({ top: 10 })
390                }, (item: string) => item)
391              }.width('100%')
392            }
393          }
394          .id("inner")
395          .width('100%')
396          .height(800)
397        }.width('100%')
398      }
399      .id("outer")
400      .height(600)
401      .scrollable(ScrollDirection.Vertical) // 滚动方向纵向
402      .scrollBar(BarState.On) // 滚动条常驻显示
403      .scrollBarColor(Color.Gray) // 滚动条颜色
404      .scrollBarWidth(10) // 滚动条宽度
405      .edgeEffect(EdgeEffect.None)
406      .shouldBuiltInRecognizerParallelWith((current: GestureRecognizer, others: Array<GestureRecognizer>) => {
407        for (let i = 0; i < others.length; i++) {
408          let target = others[i].getEventTargetInfo();
409          if (target) {
410            if (target.getId() == "inner" && others[i].isBuiltIn() && others[i].getType() == GestureControl.GestureType.PAN_GESTURE) { // 找到将要组成并行手势的识别器
411              this.currentRecognizer = current; // 保存当前组件的识别器
412              this.childRecognizer = others[i]; // 保存将要组成并行手势的识别器
413              return others[i]; // 返回将要组成并行手势的识别器
414            }
415          }
416        }
417        return undefined;
418      })
419      .onGestureRecognizerJudgeBegin((event: BaseGestureEvent, current: GestureRecognizer, others: Array<GestureRecognizer>) => { // 在识别器即将要成功时,根据当前组件状态,设置识别器使能状态
420        if (current) {
421          let target = current.getEventTargetInfo();
422          if (target) {
423            if (target.getId() == "outer" && current.isBuiltIn() && current.getType() == GestureControl.GestureType.PAN_GESTURE) {
424              if (others) {
425                for (let i = 0; i < others.length; i++) {
426                  let target = others[i].getEventTargetInfo() as ScrollableTargetInfo;
427                  if (target instanceof ScrollableTargetInfo && target.getId() == "inner") { // 找到响应链上对应并行的识别器
428                    let panEvent = event as PanGestureEvent;
429                    if (target.isEnd()) { // 根据当前组件状态以及移动方向动态控制识别器使能状态
430                      if (panEvent && panEvent.offsetY < 0) {
431                        this.childRecognizer.setEnabled(false)
432                        this.currentRecognizer.setEnabled(true)
433                      } else {
434                        this.childRecognizer.setEnabled(true)
435                        this.currentRecognizer.setEnabled(false)
436                      }
437                    } else if (target.isBegin()) {
438                      if (panEvent.offsetY > 0) {
439                        this.childRecognizer.setEnabled(false)
440                        this.currentRecognizer.setEnabled(true)
441                      } else {
442                        this.childRecognizer.setEnabled(true)
443                        this.currentRecognizer.setEnabled(false)
444                      }
445                    } else {
446                      this.childRecognizer.setEnabled(true)
447                      this.currentRecognizer.setEnabled(false)
448                    }
449                  }
450                }
451              }
452            }
453          }
454        }
455        return GestureJudgeResult.CONTINUE;
456      })
457      .parallelGesture( // 绑定一个Pan手势作为动态控制器
458        PanGesture()
459          .onActionUpdate((event: GestureEvent)=>{
460            if (this.childRecognizer.getState() != GestureRecognizerState.SUCCESSFUL || this.currentRecognizer.getState() != GestureRecognizerState.SUCCESSFUL) { // 如果识别器状态不是SUCCESSFUL,则不做控制
461              return;
462            }
463            let target = this.childRecognizer.getEventTargetInfo() as ScrollableTargetInfo;
464            let currentTarget = this.currentRecognizer.getEventTargetInfo() as ScrollableTargetInfo;
465            if (target instanceof ScrollableTargetInfo && currentTarget instanceof ScrollableTargetInfo) {
466              if (target.isEnd()) { // 在移动过程中实时根据当前组件状态,控制识别器的开闭状态
467                if ((event.offsetY - this.lastOffset) < 0) {
468                  this.childRecognizer.setEnabled(false)
469                  if (currentTarget.isEnd()) {
470                    this.currentRecognizer.setEnabled(false)
471                  } else {
472                    this.currentRecognizer.setEnabled(true)
473                  }
474                } else {
475                  this.childRecognizer.setEnabled(true)
476                  this.currentRecognizer.setEnabled(false)
477                }
478              } else if (target.isBegin()) {
479                if ((event.offsetY - this.lastOffset) > 0) {
480                  this.childRecognizer.setEnabled(false)
481                  if (currentTarget.isBegin()) {
482                    this.currentRecognizer.setEnabled(false)
483                  } else {
484                    this.currentRecognizer.setEnabled(true)
485                  }
486                } else {
487                  this.childRecognizer.setEnabled(true)
488                  this.currentRecognizer.setEnabled(false)
489                }
490              } else {
491                this.childRecognizer.setEnabled(true)
492                this.currentRecognizer.setEnabled(false)
493              }
494            }
495            this.lastOffset = event.offsetY
496          })
497      )
498    }.width('100%').height('100%').backgroundColor(0xDCDCDC)
499  }
500}
501```
502
503### 示例2
504
505本示例通过将参数exposeInnerGesture设置为true,实现了一级Tabs容器在嵌套二级Tabs的场景下,能够屏蔽二级Tabs内置Swiper的滑动手势,从而触发一级Tabs内置Swiper滑动手势的功能。
506
507```ts
508// xxx.ets
509@Entry
510@Component
511struct Index {
512  @State currentIndex: number = 0
513  @State selectedIndex: number = 0
514  @State fontColor: string = '#182431'
515  @State selectedFontColor: string = '#007DFF'
516  controller?: TabsController = new TabsController();
517  @Builder
518  tabBuilder(index: number, name: string) {
519    Column() {
520      Text(name)
521        .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
522        .fontSize(16)
523        .fontWeight(this.selectedIndex === index ? 500 : 400)
524        .lineHeight(22)
525        .margin({ top: 17, bottom: 7 })
526      Divider()
527        .strokeWidth(2)
528        .color('#007DFF')
529        .opacity(this.selectedIndex === index ? 1 : 0)
530    }.width('100%')
531  }
532  build() {
533    Column() {
534      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
535        TabContent() {
536          Column().width('100%').height('100%').backgroundColor(Color.Green)
537        }.tabBar(this.tabBuilder(0, 'green'))
538        TabContent() {
539          Tabs() {
540            TabContent() {
541              Column().width('100%').height('100%').backgroundColor(Color.Blue)
542            }.tabBar(new SubTabBarStyle('blue'))
543            TabContent() {
544              Column().width('100%').height('100%').backgroundColor(Color.Pink)
545            }.tabBar(new SubTabBarStyle('pink'))
546          }
547          .onGestureRecognizerJudgeBegin((event: BaseGestureEvent, current: GestureRecognizer,
548            others: Array<GestureRecognizer>): GestureJudgeResult => { // 在识别器即将要成功时,根据当前组件状态,设置识别器使能状态
549            console.info('ets onGestureRecognizerJudgeBegin child')
550            if (current) {
551              let target = current.getEventTargetInfo();
552              if (target && current.isBuiltIn() && current.getType() == GestureControl.GestureType.PAN_GESTURE) {
553                console.info('ets onGestureRecognizerJudgeBegin child PAN_GESTURE')
554                let swiperTaget = target as ScrollableTargetInfo
555                if (swiperTaget instanceof ScrollableTargetInfo) {
556                  console.info('ets onGestureRecognizerJudgeBegin child PAN_GESTURE isEnd: ' + swiperTaget.isEnd() + ' isBegin: ' + swiperTaget.isBegin())
557                }
558                if (swiperTaget instanceof ScrollableTargetInfo && (swiperTaget.isEnd() || swiperTaget.isBegin())) {
559                  let panEvent = event as PanGestureEvent;
560                  console.log('pan direction:' + panEvent.offsetX + ' begin:' + swiperTaget.isBegin() + ' end:' +
561                  swiperTaget.isEnd())
562                  if (panEvent && panEvent.offsetX < 0 && swiperTaget.isEnd()) {
563                    console.info('ets onGestureRecognizerJudgeBegin child reject end')
564                    return GestureJudgeResult.REJECT;
565                  }
566                  if (panEvent && panEvent.offsetX > 0 && swiperTaget.isBegin()) {
567                    console.info('ets onGestureRecognizerJudgeBegin child reject begin')
568                    return GestureJudgeResult.REJECT;
569                  }
570                }
571              }
572            }
573            return GestureJudgeResult.CONTINUE;
574          }, true)
575        }.tabBar(this.tabBuilder(1, 'blue and pink'))
576        TabContent() {
577          Column().width('100%').height('100%').backgroundColor(Color.Brown)
578        }.tabBar(this.tabBuilder(2, 'brown'))
579      }
580      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
581        // 切换动画开始时触发该回调。目标页签显示下划线。
582        this.selectedIndex = targetIndex
583      })
584    }
585  }
586}
587```
588
589 ![example](figures/gesture_recognizer.gif)