HarmonyOS鸿蒙Next中如何解决Tab组件嵌套使用时滑动事件冲突

HarmonyOS鸿蒙Next中如何解决Tab组件嵌套使用时滑动事件冲突

【问题现象】

在一个Tab组件下嵌套使用了二级Tab,当二级Tab第一个页面左滑或最后一个页面右滑不能切换到一级Tab标签的前一个Tab或后一个Tab。

点击放大

【背景知识】

【定位思路】

单独使用Tab组件可以直接触发滑动手势。但是,当Tab组件内嵌套了一个子Tab后,由于在子Tab上触发的滑动手势只能作用于当前的组件也就是子Tab上。从而导致手势触发无法作用到父组件的Tab上。

【解决方案】

把子Tab组件再嵌套在一个Column组件内,通过Column组件绑定手势触发。当Column内的Tab触发了首页右滑,或者尾页左滑时。使用TabsController控制器,来改变父Tab的标签index,从而达到控制子Tab首页右滑,或者尾页左滑时,一级Tab左右滑动的效果。

在二级Tab绑定拖动手势事件的方式,当事件触发时,用一级Tabs组件的控制器TabsController切换到一级Tabs指定页签。效果如下:

点击放大

代码示例如下:

Column() {
  //一级Tabs,并指定Tabs控制器
  Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
    TabContent() {
      Column().width('100%').height('100%').backgroundColor('#ffb554d7')
    }.tabBar(this.tabBuilder(0, '首页'))
    TabContent() {
      Column(){
        //二级Tabs
        Tabs({ barPosition: BarPosition.Start,controller: this.subController }) {
          TabContent() {
            Column().width('100%').height('100%').backgroundColor('#00CB87')
              //绑定拖动手势
              .gesture(
                // 二级Tabs第一个页签向左拖动时,触发手势事件
                PanGesture(this.panOptionLeft)
                  .onActionStart((event?: GestureEvent) => {
                    console.info('Pan start')
                  })
                  // 通过父组件的TabsController的实例,改变其index,达到跳转一级Tabs(首页)的效果
                  .onActionEnd(() => {
                    this.controller.changeIndex(0)
                    console.info('Pan end')
                  })
              )
          }.tabBar(this.subTabBuilder(0, 'green'))
          TabContent() {
            Column().width('100%').height('100%').backgroundColor('#007DFF')
          }.tabBar(this.subTabBuilder(1, 'blue'))
          TabContent() {
            Column().width('100%').height('100%').backgroundColor('#FFBF00')
          }.tabBar(this.subTabBuilder(2, 'yellow'))
          TabContent() {
            Column().width('100%').height('100%').backgroundColor('#E67C92')
              .gesture(
                  // 二级Tabs最后一个页签向右拖动时,触发手势事件
                PanGesture(this.panOptionRight)
                  .onActionStart((event?: GestureEvent) => {
                    console.info('Pan start')
                  })
                  // 通过父组件的TabsController的实例,改变其index,达到跳转一级Tabs(首页)的效果
                  .onActionEnd(() => {
                    this.controller.changeIndex(2)
                    console.info('Pan end')
                  })
              )
          }.tabBar(this.subTabBuilder(3, 'pink'))
        }
        .vertical(false)
        .barMode(BarMode.Fixed)
        .barWidth(360)
        .barHeight(56)
        .animationDuration(400)
        .onChange((index: number) => {
          this.subCurrentIndex = index
        })
        .width(360)
        .backgroundColor('#F1F3F5')
      }
      .width('100%').height('100%').backgroundColor('#00CB87')
    }.tabBar(this.tabBuilder(1, '详情'))
    TabContent() {
      Column().width('100%').height('100%').backgroundColor('#ffc19757')
    }.tabBar(this.tabBuilder(2, '我的'))
  }
  .vertical(false)
  .barMode(BarMode.Fixed)
  .barWidth(360)
  .barHeight(56)
  .animationDuration(400)
  .onChange((index: number) => {
    this.currentIndex = index
  })
  .width(360)
  .height(296)
  .margin({ top: 52 })
  .backgroundColor('#F1F3F5')
}.width('100%')

【总结】

ArkUI为开发提供了完整的基础设施和丰富的能力,灵活的运用各种组件的能力,可以让开发者实现预期的效果。从而为最终使用者提供丰富、良好的交互体验。


更多关于HarmonyOS鸿蒙Next中如何解决Tab组件嵌套使用时滑动事件冲突的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中如何解决Tab组件嵌套使用时滑动事件冲突的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


将子Tab组件嵌套在Column组件内

通过Column组件绑定手势触发。当二级Tab的第一个页面左滑或最后一个页面右滑时,使用TabsController控制器改变一级Tab的标签index,实现一级Tab的左右滑动效果。具体代码示例如下:

Column() {
  Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
    TabContent() {
      Column().width('100%').height('100%').backgroundColor('#ffb554d7')
    }.tabBar(this.tabBuilder(0, '首页'))
    TabContent() {
      Column() {
        Tabs({ barPosition: BarPosition.Start, controller: this.subController }) {
          TabContent() {
            Column().width('100%').height('100%').backgroundColor('#00CB87')
              .gesture(
                PanGesture(this.panOptionLeft)
                  .onActionStart((event?: GestureEvent) => {
                    console.info('Pan start')
                  })
                  .onActionEnd(() => {
                    this.controller.changeIndex(0)
                    console.info('Pan end')
                  })
              )
          }.tabBar(this.subTabBuilder(0, 'green'))
          TabContent() {
            Column().width('100%').height('100%').backgroundColor('#007DFF')
          }.tabBar(this.subTabBuilder(1, 'blue'))
          TabContent() {
            Column().width('100%').height('100%').backgroundColor('#FFBF00')
          }.tabBar(this.subTabBuilder(2, 'yellow'))
          TabContent() {
            Column().width('100%').height('100%').backgroundColor('#E67C92')
              .gesture(
                PanGesture(this.panOptionRight)
                  .onActionStart((event?: GestureEvent) => {
                    console.info('Pan start')
                  })
                  .onActionEnd(() => {
                    this.controller.changeIndex(2)
                    console.info('Pan end')
                  })
              )
          }.tabBar(this.subTabBuilder(3, 'pink'))
        }
        .vertical(false)
        .barMode(BarMode.Fixed)
        .barWidth(360)
        .barHeight(56)
        .animationDuration(400)
        .onChange((index: number) => {
          this.subCurrentIndex = index
        })
        .width(360)
        .backgroundColor('#F1F3F5')
      }
      .width('100%').height('100%').backgroundColor('#00CB87')
    }.tabBar(this.tabBuilder(1, '详情'))
    TabContent() {
      Column().width('100%').height('100%').backgroundColor('#ffc19757')
    }.tabBar(this.tabBuilder(2, '我的'))
  }
  .vertical(false)
  .barMode(BarMode.Fixed)
  .barWidth(360)
  .barHeight(56)
  .animationDuration(400)
  .onChange((index: number) => {
    this.currentIndex = index
  })
  .width(360)
  .height(296)
  .margin({ top: 52 })
  .backgroundColor('#F1F3F5')
}.width('100%')
回到顶部