如何实现双层Swiper组件嵌套联动
==================

#### 问题现象

Swiper组件嵌套Swiper，当子组件滑动到首页或尾页边界时，如何实现子组件索引不变，父组件滑动到上一个或下一个页签。

#### 效果预览

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/9e/v3/xkzTUvZRTdad9KZ2wAgFoA/zh-cn_image_0000002628763650.png?HW-CC-KV=V1&HW-CC-Date=20260709T133950Z&HW-CC-Expire=86400&HW-CC-Sign=E72D8B6B148FDF325C19E889DC92FC6D1A1AB7AA43F9EB6B55184A6C751BDA51 "点击放大")

#### 背景知识

*   [Swiper：](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper)滑块视图容器，提供子组件滑动轮播显示的能力。
*   [onGestureRecognizerJudgeBegin：](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-gesture-blocking-enhancement#ongesturerecognizerjudgebegin13)自定义手势识别器判定回调。通过记录子组件Swiper的索引值，判断当滑动达到子组件Swiper的边界处时，触发回调返回屏蔽使父组件Swiper产生滑动手势。
*   [PanGesture](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-gestures-pangesture)：滑动手势事件，当滑动的最小距离达到设定的最小值时触发滑动手势事件。

#### 解决方案

*   **方案一**：通过获取Swiper子组件进行手势滑动时的velocityX（当前手势的x轴方向速度）和索引值，判断当滑动达到子组件Swiper的边界处时，触发回调返回屏蔽使父组件Swiper产生滑动手势。
    
    @Entry
    @Component
    struct NestedSwiperExample {
      private swiperController: SwiperController \= new SwiperController();
     _ // 外层Swiper的数据_
      private outerSwiperData: string\[\] \= \['Page 1', 'Page 2', 'Page 3'\];
     _ // 内层Swiper的数据_
      private innerSwiperData: string\[\] \= \['Image 1', 'Image 2', 'Image 3'\];
     _ // 外层Swiper的索引_
      @State outerIndex: number \= 0;
      _// 内层Swiper的索引_
      @State innerIndex: number \= 0;
    
      build() {
        Swiper(this.swiperController) {
          ForEach(this.outerSwiperData, (outerItem: string) \=\> {
            Column() {
              Text(outerItem)
                .fontSize(24)
                .margin({ top: 20, bottom: 20 });
    
              Swiper() {
                ForEach(this.innerSwiperData, (innerItem: string) \=\> {
                  Column() {
                    Text(innerItem)
                      .fontSize(18);
                  }
                  .width('100%')
                  .height(200)
                  .backgroundColor('#e0e0e0')
                  .margin({ bottom: 10 })
                });
              }
              .width('100%')
              .height(200)
              .autoPlay(false)
              .loop(true)
              .index(this.innerIndex)
              .onAnimationStart((index: number, targetIndex: number) \=\> {
                console.info('index', index);
                this.innerIndex \= targetIndex;
              })
              .onGestureRecognizerJudgeBegin((event: BaseGestureEvent, current: GestureRecognizer,
                others: Array<GestureRecognizer\>): GestureJudgeResult \=\> { _// 在识别器即将要成功时，根据当前组件状态，设置识别器使能状态_
                console.info('others', others);
                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.innerIndex \=== 2) { _// 内层Swiper滑动到尾页_
                      this.innerIndex \= 0;
                      console.info('ets onGestureRecognizerJudgeBegin child reject end');
                      return GestureJudgeResult.REJECT;
                    }
                    if (panEvent && panEvent.velocityX \> 0 && this.innerIndex \=== 0) { _// 内层Swiper滑动到首页_
                      console.info('ets onGestureRecognizerJudgeBegin child reject begin');
                      this.innerIndex \= 0;
                      return GestureJudgeResult.REJECT;
                    }
                  }
                }
                return GestureJudgeResult.CONTINUE;
              }, true)
            }
            .width('100%')
            .height('100%');
          });
        }
        .width('100%')
        .height('100%')
        .autoPlay(false)
        .loop(false)
        .index(this.outerIndex)
        .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) \=\> {
          console.info('index', index);
          console.info('event', event);
          this.outerIndex \= targetIndex;
        })
      }
    }
    
*   **方案二**：通过PanGesture手势获取滑动的速度和索引值，判断当滑动达到子组件Swiper的边界处时，调用父组件showNext()和showPrevious()方法，来控制父组件滑动到上一个和下一个页签。示例代码如下：
    
    @Entry
    @Component
    struct SwiperExample {
      private swiperController: SwiperController \= new SwiperController();
     _ // 外层Swiper的数据_
      private outerSwiperData: string\[\] \= \['Page 1', 'Page 2', 'Page 3'\];
      _// 内层Swiper的数据_
      private innerSwiperData: string\[\] \= \['Image 1', 'Image 2', 'Image 3'\];
     _ // 外层Swiper的索引_
      @State outerIndex: number \= 0;
      _// 内层Swiper的索引_
      @State innerIndex: number \= 0;
    
      build() {
        Swiper(this.swiperController) {
          ForEach(this.outerSwiperData, (outerItem: string) \=\> {
            Column() {
              Text(outerItem)
                .fontSize(24)
                .margin({ top: 20, bottom: 20 });
    
              Swiper() {
                ForEach(this.innerSwiperData, (innerItem: string) \=\> {
                  Column() {
                    Text(innerItem)
                      .fontSize(18);
                  }
                  .width('100%')
                  .height(200)
                  .backgroundColor('#e0e0e0')
                  .margin({ bottom: 10 });
                });
              }
              .width('100%')
              .height(200)
              .autoPlay(false)
              .loop(false)
              .index(this.innerIndex)
              .onAnimationStart((index: number, targetIndex: number) \=\> {
                console.info('index', index);
                this.innerIndex \= targetIndex;
              })
              .parallelGesture(
                PanGesture()
                  .onActionEnd((e) \=\> {
                    let velocityX \= e.velocityX || 0; _// 手势结束，获取当前的速度_
                    if (velocityX < 0 && this.innerIndex \=== 2) {
                      this.innerIndex \= 0;
                      this.swiperController.showNext(); _// x轴方向速度小于0时，向左移动_
                    }
                    if (velocityX \> 0 && this.innerIndex \=== 0) {
                      this.innerIndex \= 0;
                      this.swiperController.showPrevious(); _// x轴方向速度大于0时，向右移动_
                    }
                  })
              )
            }
            .width('100%')
            .height('100%');
          });
        }
        .width('100%')
        .height('100%')
        .autoPlay(false)
        .loop(false)
        .index(this.outerIndex)
        .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) \=\> {
          this.outerIndex \= targetIndex;
          console.info('index', index);
          console.info('event', event);
        })
      }
    }