harmony 鸿蒙手势拦截增强

  • 2025-06-12
  • 浏览 (4)

手势拦截增强

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

说明:

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

shouldBuiltInRecognizerParallelWith

shouldBuiltInRecognizerParallelWith(callback: ShouldBuiltInRecognizerParallelWithCallback): T

提供系统内置手势与响应链上其他组件的手势设置并行关系的回调事件。此接口对应的capi接口为setInnerGestureParallelTo

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

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

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

返回值:

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

ShouldBuiltInRecognizerParallelWithCallback

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

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

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

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

参数:

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

返回值:

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

TouchRecognizer20+

触摸识别器对象。

原子化服务API: 从API version 20开始,该接口支持在原子化服务中使用。

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

getEventTargetInfo20+

getEventTargetInfo(): EventTargetInfo

返回组件的事件目标信息。

原子化服务API: 从API version 20开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
EventTargetInfo 组件的事件目标信息。

cancelTouch20+

cancelTouch(): void

向识别器发送触摸取消事件。

原子化服务API: 从API version 20开始,该接口支持在原子化服务中使用。

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

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 当前手势识别器是否为系统内置手势。true表示手势识别器为系统内置手势,false表示非系统内置手势。

setEnabled

setEnabled(isEnabled: boolean): void

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

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

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

参数:

参数名 类型 必填 说明
isEnabled boolean 手势识别器的使能状态。true表示当前手势识别器能够回调应用事件,false表示当前手势识别器不回调应用事件。

isEnabled

isEnabled(): boolean

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

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

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

返回值:

类型 说明
boolean 当前手势识别器的使能状态。true表示当前手势识别器能够回调应用事件,false表示当前手势识别器不回调应用事件。

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。

getFingerCount18+

getFingerCount(): number

返回预设手指识别数阈值。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
number 预设手指识别数阈值。
取值范围:[1, 10], 整数。

isFingerCountLimit18+

isFingerCountLimit(): boolean

返回预设手势是否会检测触摸屏幕上手指识别数量。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
boolean 预设手势是否会检测触摸屏幕上手指识别数量。当绑定手势事件且会检测触摸屏幕上手指的数量时,返回true。当绑定手势事件且不会检测触摸屏幕上手指的数量时,返回false。

preventBegin20+

preventBegin(): void

阻止手势识别器参与手势处理。

原子化服务API: 从API version 20开始,该接口支持在原子化服务中使用。

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

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 当前滚动类容器组件是否在顶部。true表示组件在顶部,false表示组件不在顶部。

isEnd

isEnd(): boolean

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

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

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

返回值:

类型 说明
boolean 当前滚动类容器组件是否在底部。true表示组件在底部,false表示组件不在底部。

PanRecognizer

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

getPanGestureOptions

getPanGestureOptions(): PanGestureOptions

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

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

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

返回值:

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

getDirection19+

getDirection(): PanDirection

返回当前拖动手势识别器的方向。

原子化服务API: 从API version 19开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
PanDirection 当前拖动手势识别器的方向。

getDistance19+

getDistance(): number

返回当前拖动手势识别器触发的最小滑动距离。

原子化服务API: 从API version 19开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
number 当前拖动手势识别器触发的最小滑动距离。

getDistanceMap19+

getDistanceMap(): Map<SourceTool, number>

返回不同输入源的拖动手势识别器触发的最小滑动距离。

原子化服务API: 从API version 19开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
Map<SourceTool, number> 不同输入源的拖动手势识别器触发的最小滑动距离。

TapRecognizer18+

点击手势识别器对象,继承于GestureRecognizer

getTapCount18+

getTapCount(): number

返回预设点击手势识别器连续点击次数阈值。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
number 预设点击手势识别器连续点击次数阈值。
取值范围:[0, +∞)

LongPressRecognizer18+

长按手势识别器对象,继承于GestureRecognizer

isRepeat18+

isRepeat(): boolean

返回预设长按手势识别器是否连续触发事件回调。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
boolean 预设长按手势识别器是否连续触发事件回调。当绑定长按手势且不会连续触发回调时,返回false。当绑定长按手势且会连续触发回调时,返回true。

getDuration18+

getDuration(): number

返回预设长按手势识别器触发长按最短时间阈值。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
number 返回预设长按手势识别器触发长按最短时间阈值,单位为ms。
取值范围:[0, +∞)

SwipeRecognizer18+

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

getVelocityThreshold18+

getVelocityThreshold(): number

返回预设滑动手势识别器识别滑动最小速度阈值。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
number 预设滑动手势识别器识别滑动最小速度阈值,单位为vp/s。
取值范围:[0, +∞)

getDirection18+

getDirection(): SwipeDirection

返回预设滑动手势识别器触发滑动手势滑动方向。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
SwipeDirection 预设滑动手势识别器触发滑动手势滑动方向。

PinchRecognizer18+

捏合手势识别器对象,继承于GestureRecognizer

getDistance18+

getDistance(): number

返回预设捏合手势识别器最小识别距离阈值。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
number 预设捏合手势识别器最小识别距离阈值,单位为vp。
取值范围:[0, +∞)

RotationRecognizer18+

旋转手势识别器对象,继承于GestureRecognizer

getAngle18+

getAngle(): number

返回预设旋转手势识别器触发旋转手势最小改变度数阈值。

原子化服务API: 从API version 18开始,该接口支持在原子化服务中使用。

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

返回值:

类型 说明
number 预设旋转手势识别器触发旋转手势最小改变度数阈值,单位为deg。
取值范围:[0, +∞)
说明:
当输入的改变度数的值小于等于0或大于360时,会被转化为默认值,默认值为1。

onGestureRecognizerJudgeBegin13+

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<GestureRecognizer>, touchRecognizers?: Array<TouchRecognizer>) => GestureJudgeResult

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

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

参数:

参数名 类型 必填 说明
event BaseGestureEvent 当前基础手势事件信息。
原子化服务API: 从API version 12开始,该接口支持在原子化服务中使用。
current GestureRecognizer 当前即将要响应的识别器对象。
原子化服务API: 从API version 12开始,该接口支持在原子化服务中使用。
others Array<GestureRecognizer> 响应链上的其他手势识别器对象。
原子化服务API: 从API version 12开始,该接口支持在原子化服务中使用。
touchRecognizers20+ Array<TouchRecognizer> 响应链上的Touch识别器对象。 默认值为null,表示在当前手势绑定组件及其子孙组件没有可响应的Touch识别器。
原子化服务API: 从API version 20开始,该接口支持在原子化服务中使用。

返回值:

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

onTouchTestDone20+

onTouchTestDone(callback: TouchTestDoneCallback): T

提供在触摸测试结束后,指定手势识别器是否参与后续处理的能力。

原子化服务API: 从API version 20开始,该接口支持在原子化服务中使用。

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

参数:

参数名 类型 必填 说明
callback TouchTestDoneCallback 回调函数,用于指定手势识别器是否参与后续处理。在触摸测试结束后,开始识别用户手势之前,会触发该回调来动态指定手势识别器是否参与手势处理。

返回值:

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

TouchTestDoneCallback20+

type TouchTestDoneCallback = (event: BaseGestureEvent, recognizers: Array<GestureRecognizer>) => void

动态指定手势识别器是否参与手势处理的回调事件类型。

原子化服务API: 从API version 20开始,该接口支持在原子化服务中使用。

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

参数:

参数名 类型 必填 说明
event BaseGestureEvent 当前基础手势事件信息。
recognizers Array<GestureRecognizer> 触摸测试结束后,所有手势识别器对象。

示例

示例1(嵌套滚动)

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

// xxx.ets
@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产生滑动手势。

// xxx.ets
@Entry
@Component
struct Index {
  @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() {
    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 panEvent = event as PanGestureEvent;
                if (panEvent && panEvent.velocityX < 0 && this.innerSelectedIndex === 1) { // 内层Tabs滑动到尽头
                  console.info('ets onGestureRecognizerJudgeBegin child reject end')
                  return GestureJudgeResult.REJECT;
                }
                if (panEvent && panEvent.velocityX > 0 && this.innerSelectedIndex === 0) { // 内层Tabs滑动到开头
                  console.info('ets onGestureRecognizerJudgeBegin child reject begin')
                  return GestureJudgeResult.REJECT;
                }
              }
            }
            return GestureJudgeResult.CONTINUE;
          }, true)
        }.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
      })
    }
  }
}

example

示例3(拦截手势获取属性)

该示例通过配置onGestureRecognizerJudgeBegin判定手势,获取相应属性参数。

// xxx.ets
@Entry
@Component
struct Index {
  @State message: string = 'Gesture';

  build() {
    Column() {
      Row({ space: 20 }) {
        Text(this.message)
          .width(400)
          .height(80)
          .fontSize(23)
      }.margin(25)
    }
    .margin(50)
    .width(400)
    .height(200)
    .borderWidth(2)
    .gesture(TapGesture())
    .gesture(LongPressGesture())
    .gesture(PanGesture({ direction: PanDirection.Vertical }))
    .gesture(PinchGesture())
    .gesture(RotationGesture())
    .gesture(SwipeGesture({ direction: SwipeDirection.Horizontal }))
    //通过给组件绑定自定义手势识别器判定回调
    .onGestureRecognizerJudgeBegin((event: BaseGestureEvent, current: GestureRecognizer,
      others: Array<GestureRecognizer>) => {
      if (current) {
        //判断是否为拖动手势
        if (current.getType() == GestureControl.GestureType.PAN_GESTURE) {
          let target = current as PanRecognizer;
          this.message = 'PanGesture\ndistance:' + target.getPanGestureOptions().getDistance() + '\nfingers:' +
          target.getFingerCount() + '\nisFingerCountLimited:' + target.isFingerCountLimit();
        }
        //判断是否为长按手势
        if (current.getType() == GestureControl.GestureType.LONG_PRESS_GESTURE) {
          let target = current as LongPressRecognizer;
          this.message = 'LongPressGesture\nfingers:' + target.getFingerCount() + '\nisFingerCountLimited:' +
          target.isFingerCountLimit() + '\nrepeat:' + target.isRepeat() + '\nduration:' + target.getDuration();
        }
        //判断是否为捏合手势
        if (current.getType() == GestureControl.GestureType.PINCH_GESTURE) {
          let target = current as PinchRecognizer;
          this.message = 'PinchGesture\ndistance:' + target.getDistance() + '\nfingers:' +
          target.getFingerCount() + '\nisFingerCountLimited:' + target.isFingerCountLimit();
        }
        //判断是否为点击手势
        if (current.getType() == GestureControl.GestureType.TAP_GESTURE) {
          let target = current as TapRecognizer;
          this.message = 'TapGesture\ncount:' + target.getTapCount() + '\nfingers:' +
          target.getFingerCount() + '\nisFingerCountLimited:' + target.isFingerCountLimit();
        }
        //判断是否为旋转手势
        if (current.getType() == GestureControl.GestureType.ROTATION_GESTURE) {
          let target = current as RotationRecognizer;
          this.message = 'RotationGesture\nangle:' + target.getAngle() + '\nfingers:' +
          target.getFingerCount() + '\nisFingerCountLimited:' + target.isFingerCountLimit();
        }
        //判断是否为滑动手势
        if (current.getType() == GestureControl.GestureType.SWIPE_GESTURE) {
          let target = current as SwipeRecognizer;
          this.message = 'SwipeGesture\ndirection:' + target.getDirection() + '\nfingers:' +
          target.getFingerCount() + '\nisFingerCountLimited:' + target.isFingerCountLimit() + '\nspeed:' +
          target.getVelocityThreshold();
        }
      }
      return GestureJudgeResult.CONTINUE;
    })
  }
}

example

### 示例4(手势触发成功时取消子组件上的Touch事件)

该示例通过配置onGestureRecognizerJudgeBegin判定手势,在父容器手势触发成功时,调用cancelTouch()强制取消子组件上的Touch事件,实现父子组件手势控制的精准切换。

 // xxx.ets
@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;
  @State innerState: string = "IDLE"; // 内部滚动容器状态
  @State stateHistory: string[] = ["状态历史:"]; // 状态变化历史记录

  updateState(newState: string) {
    this.innerState = newState;
    this.stateHistory.push(` ${newState}`);

    if (this.stateHistory.length > 10) {
      this.stateHistory = this.stateHistory.slice(this.stateHistory.length - 10);
    }
  }

  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)
          .onTouch((event) => {
            if (event.type === TouchType.Down) {
              this.updateState("TOUCHING");
            } else if (event.type === TouchType.Up||event.type === TouchType.Cancel) {
              this.updateState("IDLE");
            }
          })
        }.width('100%')
      }
      .id("outer")
      .height('100%')
      .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>,
        touchRecognizers?: Array<TouchRecognizer>) => {
        if (current && touchRecognizers) {
          let target = current.getEventTargetInfo();
          if (target) {
            if (target.getId() == "outer" && current.isBuiltIn() &&
              current.getType() == GestureControl.GestureType.PAN_GESTURE) {
              return GestureJudgeResult.CONTINUE
            }
            for (let index = 0; index < touchRecognizers.length; index++) {
              const element = touchRecognizers![index];
              let touchTarget = element.getEventTargetInfo()
              if (touchTarget && touchTarget.getId() == "inner") {
                this.updateState("CANCELLED");
                element.cancelTouch()
              }
            }
          }
        }
        return GestureJudgeResult.CONTINUE;
      })
      .onTouch((event) => {
        if (event.type === TouchType.Down) {
          this.updateState("OUTER_TOUCHING");
        }
      })
      .parallelGesture(
        PanGesture()
          .onActionUpdate((event: GestureEvent) => {
            if (this.childRecognizer.getState() != GestureRecognizerState.SUCCESSFUL||
              this.currentRecognizer.getState() != GestureRecognizerState.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
          })
      )

      // 状态显示区域
      Column() {
        // 当前状态显示
        Text(`当前状态: ${this.innerState}`)
          .fontSize(20)
          .fontColor(this.getStateColor(this.innerState))
          .margin({ bottom: 10 })

        // 状态历史记录
        ForEach(this.stateHistory, (item: string) => {
          Text(item)
            .fontSize(20)
            .textAlign(TextAlign.Start)
            .margin({ left: 10, top: 4 })
        }, (item: string) => item)
      }
      .width('90%')
      .height(240)
      .backgroundColor(Color.White)
      .border({ width: 1, color: Color.Gray })
      .position({ x: '5%', y: '75%' })
      .margin({ top: -160 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(0xDCDCDC)
  }

  // 根据状态返回不同颜色
  private getStateColor(state: string): Color {
    switch (state) {
      case "IDLE":
        return Color.Gray;
      case "TOUCHING":
        return Color.Blue;
      case "CANCELLED":
        return Color.Red;
      case "OUTER_TOUCHING":
        return Color.Green;
      default:
        return Color.Black;
    }
  }
}

example

### 示例5(自定义手势识别器是否参与手势处理)

该示例通过配置onTouchTestDone指定手势识别器不参与后续手势处理,触发回调时,调用preventBegin()阻止手势识别器参与后续处理。

// xxx.ets
@Entry
@Component
struct TouchTestDoneExample {
  @State tagList: string[] = ['Null', 'Tap1', 'Tap2', 'Tap3', 'Tap4'];
  @State tagId: number = 0;
  @State textValue: string = '';

  // 多层嵌套场景,为每一层的组件绑定一个Tap手势
  build() {
    Column() {
      Column() {
        Text('Tap1')
          .margin(20)
        Column() {
          Text('Tap2')
            .margin(20)
          Column() {
            Text('Tap3')
              .margin(20)
            Column() {
              Text('Tap4')
                .margin(20)
            }
            .backgroundColor('#D5D5D5')
            .width('80%')
            .height('80%')
            .gesture(TapGesture().tag('Tap4').onAction(() => {
              this.textValue = 'Tap4';
            }))
          }
          .backgroundColor('#F7F7F7')
          .width('80%')
          .height('80%')
          .gesture(TapGesture().tag('Tap3').onAction(() => {
            this.textValue = 'Tap3';
          }))
        }
        .backgroundColor('#707070')
        .width('80%')
        .height('80%')
        .gesture(TapGesture().tag('Tap2').onAction(() => {
          this.textValue = 'Tap2';
        }))
      }
      .backgroundColor('#D5D5D5')
      .width('80%')
      .height('80%')
      .gesture(TapGesture().tag('Tap1').onAction(() => {
        this.textValue = 'Tap1';
      }))
      .onTouchTestDone((event, recognizers) => {
        console.info('event is ' + JSON.stringify(event));
        for (let i = 0; i < recognizers.length; i++) {
          let recognizer = recognizers[i];
          console.info('type is ' + JSON.stringify(recognizer.getType()))
          // 根据tag的值屏蔽不同的手势识别器
          if (recognizer.getTag() == this.tagList[this.tagId]) {
            recognizer.preventBegin();
          }
        }
      })

      Text('Current Gesture: ' + this.textValue)
        .margin(5)

      Button('Click to change preventGesture')
        .margin(5)
        .onClick(() => {
          this.tagId++;
          this.tagId %= 5;
        })
      Text('Current prevent gesture tag: ' + this.tagList[this.tagId])
        .margin(5)

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

    // 示例gif中,点击Tap2和Tap1的重合区域,不调用preventBegin时,触发的为Tap2手势;调用preventBegin阻止Tap2时,触发的为Tap1手势
  }
}

example

你可能感兴趣的鸿蒙文章

harmony 鸿蒙图像AI分析错误码

harmony 鸿蒙ArcButton

harmony 鸿蒙ArcSlider

harmony 鸿蒙Chip

harmony 鸿蒙ChipGroup

harmony 鸿蒙ComposeListItem

harmony 鸿蒙ComposeTitleBar

harmony 鸿蒙advanced.Counter

harmony 鸿蒙弹出框 (Dialog)

harmony 鸿蒙DialogV2

0  赞