当前位置: 首页 > article >正文

【鸿蒙 HarmonyOS NEXT】组件嵌套滚动:nestedScroll

✨本人自己开发的开源项目:土拨鼠充电系统

✨踩坑不易,还希望各位大佬支持一下,在GitHub给我点个 Start ⭐⭐👍👍

GitHub开源项目地址👉:https://github.com/cheinlu/groundhog-charging-system

一、背景

当滚动组件进行嵌套关系时,如果两个组件需要同时滚动可能会产生互斥效果,使用nestedScroll属性来解决嵌套组件的滚动问题

可滚动组件:Scroll、List、WaterFlow,这些组件中都有包含nestedScroll属性,用于解决组件嵌套的滚动联动

二、场景

tabs嵌套list组件,当tabs切换页签时,会与list组件的滚动出现互斥效果,期望按住文本或按钮区域都能实现切换页签效果

具体描述:

tabs下面展示文本信息与按钮,其中按钮是用list组件完成的,当按钮多的情况下是可以滚动按钮,目前问题是按住文本区域是可以左右切换tabs页签的,按住按钮区域切换tab就不行,怀疑是list滚动与tab页签切换互斥了

三、具体实现

3.1、示例代码

@Entry
@Component
struct TabsExample {
  @State fontColor: string = '#182431'
  @State selectedFontColor: string = '#007DFF'
  @State currentIndex: number = 0
  private controller: TabsController = new TabsController()

  @Builder
  tabBuilder(index: number, name: string) {
    Column() {
      Text(name)
        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
        .fontSize(16)
        .fontWeight(this.currentIndex === index ? 500 : 400)
        .lineHeight(22)
        .margin({ top: 17, bottom: 7 })
      Divider()
        .strokeWidth(2)
        .color('#007DFF')
        .opacity(this.currentIndex === index ? 1 : 0)
    }.width('100%')
  }

  build() {
    Column() {
      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
        TabContent() {
          OrderList({ type: '1' })
        }
        .tabBar(this.tabBuilder(0, 'green'))
        .gesture(PanGesture(new PanGestureOptions({ direction: PanDirection.Right })))

        TabContent() {
          OrderList({ type: '2' })
        }.tabBar(this.tabBuilder(1, 'blue'))

        TabContent() {
          OrderList({ type: '3' })
        }.tabBar(this.tabBuilder(2, 'yellow'))

        TabContent() {
          OrderList({ type: '4' })
        }
        .tabBar(this.tabBuilder(3, 'pink'))
        .gesture(PanGesture(new PanGestureOptions({ direction: PanDirection.Left })))
      }
      .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%')
  }
}


@Component
struct OrderList {
  @Prop type: string

  build() {
    Column() {
      Column({ space: 30 }) {
        Row() {
          Text('文本' + this.type)
        }

        Row() {
          Text('文本' + this.type)
        }

        Row() {
          Text('文本' + this.type)
        }
      }
      .width('100%')
      .height(150)

      List() {
        ListItem() {
          Row() {
            Text('取消订单' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }

        ListItem() {
          Row() {
            Text('查看发票' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }

        ListItem() {
          Row() {
            Text('申请发票' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }

        ListItem() {
          Row() {
            Text('退换货' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }

        ListItem() {
          Row() {
            Text('去支付' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }
      }
      .listDirection(Axis.Horizontal)
      .scrollBar(BarState.Off)
      .edgeEffect(EdgeEffect.None)
      .width('100%')
    }
    .width('100%')
  }
}

3.2、实现效果 

3.3、完成预期效果:按住按钮区域也能切换页签

解决方法:给list添加nestedScroll属性,解决嵌套组件的滚动问题

详细代码:


@Entry
@Component
struct TabsExample {
  @State fontColor: string = '#182431'
  @State selectedFontColor: string = '#007DFF'
  @State currentIndex: number = 0
  private controller: TabsController = new TabsController()

  @Builder
  tabBuilder(index: number, name: string) {
    Column() {
      Text(name)
        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
        .fontSize(16)
        .fontWeight(this.currentIndex === index ? 500 : 400)
        .lineHeight(22)
        .margin({ top: 17, bottom: 7 })
      Divider()
        .strokeWidth(2)
        .color('#007DFF')
        .opacity(this.currentIndex === index ? 1 : 0)
    }.width('100%')
  }

  build() {
    Column() {
      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
        TabContent() {
          OrderList({ type: '1' })
        }
        .tabBar(this.tabBuilder(0, 'green'))
        .gesture(PanGesture(new PanGestureOptions({ direction: PanDirection.Right })))

        TabContent() {
          OrderList({ type: '2' })
        }.tabBar(this.tabBuilder(1, 'blue'))

        TabContent() {
          OrderList({ type: '3' })
        }.tabBar(this.tabBuilder(2, 'yellow'))

        TabContent() {
          OrderList({ type: '4' })
        }
        .tabBar(this.tabBuilder(3, 'pink'))
        .gesture(PanGesture(new PanGestureOptions({ direction: PanDirection.Left })))
      }
      .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%')
  }
}


@Component
struct OrderList {
  @Prop type: string

  build() {
    Column() {
      Column({ space: 30 }) {
        Row() {
          Text('文本' + this.type)
        }

        Row() {
          Text('文本' + this.type)
        }

        Row() {
          Text('文本' + this.type)
        }
      }
      .width('100%')
      .height(150)

      List() {
        ListItem() {
          Row() {
            Text('取消订单' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }

        ListItem() {
          Row() {
            Text('查看发票' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }

        ListItem() {
          Row() {
            Text('申请发票' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }

        ListItem() {
          Row() {
            Text('退换货' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }

        ListItem() {
          Row() {
            Text('去支付' + this.type).fontSize(13).fontColor('#222427')
          }
          .padding({
            left: 12,
            right: 12,
            top: 5,
            bottom: 5
          })
          .border({
            width: 1,
            radius: 4,
            color: '#C9CED3',
            style: BorderStyle.Solid
          })
        }
      }
      .listDirection(Axis.Horizontal)
      .scrollBar(BarState.Off)
      .edgeEffect(EdgeEffect.None)
      .width('100%')
      .nestedScroll({
        scrollForward: NestedScrollMode.SELF_FIRST,
        scrollBackward: NestedScrollMode.SELF_FIRST
      })
    }
    .width('100%')
  }
}

四、nestedScroll介绍

nestedScroll:设置向前向后两个方向上的嵌套滚动模式,实现与父组件的滚动联动。

参数名类型必填说明
valueNestedScrollOptions嵌套滚动选项。

NestedScrollOptions对象说明

名称类型必填描述
scrollForwardNestedScrollMode滚动组件往末尾端滚动时的嵌套滚动选项。
scrollBackwardNestedScrollMode滚动组件往起始端滚动时的嵌套滚动选项。

NestedScrollMode枚举说明

名称描述
SELF_ONLY只自身滚动,不与父组件联动。
SELF_FIRST自身先滚动,自身滚动到边缘以后父组件滚动。父组件滚动到边缘以后,如果父组件有边缘效果,则父组件触发边缘效果,否则子组件触发边缘效果。
PARENT_FIRST父组件先滚动,父组件滚动到边缘以后自身滚动。自身滚动到边缘后,如果有边缘效果,会触发自身的边缘效果,否则触发父组件的边缘效果。
PARALLEL自身和父组件同时滚动,自身和父组件都到达边缘以后,如果自身有边缘效果,则自身触发边缘效果,否则父组件触发边缘效果。

http://www.kler.cn/a/318209.html

相关文章:

  • vite + vue3 + ts解决别名引用@/api/user报错找不到相应的模块
  • 大模型研究报告 | 2024年中国金融大模型产业发展洞察报告|附34页PDF文件下载
  • CSS:怎么把网站都变成灰色
  • 第三十一天|贪心算法| 56. 合并区间,738.单调递增的数字 , 968.监控二叉树
  • 随时随地编码:香橙派Zero3上安装Code Server远程开发指南
  • 《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址
  • 【html】基础(二)
  • 量化交易----数据透视表----融资融券优惠代码
  • 响应式布局-媒体查询父级布局容器
  • spring boot导入多个配置文件
  • #C++ enum枚举
  • Qt/C++ 多线程同步机制详解及应用
  • Shiro-550—漏洞分析(CVE-2016-4437)
  • 详解QT插件机制
  • ARM/Linux嵌入式面经(三三):大疆
  • zabbix email 告警
  • [大语言模型-论文精读] ACL2024-长尾知识在检索增强型大型语言模型中的作用
  • Invalid Executable The executable contains bitcode
  • 报错error: RPC failed,curl 16 Error in the HTTP2 framing layer解决方法
  • 自动化学习3:日志记录及测试报告的生成--自动化框架搭建
  • 数据库课程 CMU15-445 2023 Fall Project-2 Extendible Hash Index
  • WebAssembly (Wasm) 与 JavaScript 字符串交互
  • shardingjdbc分库分表原理
  • 实战16-RVP定义完成适配
  • rocky9.2的lvs的NAT模式下的基本使用的详细示例
  • SpringBoot使用@Async注解,实现异步任务