鸿蒙实现可以上下左右滑动的表格-摆脱大量ListScroller

鸿蒙实现可以上下左右滑动的表格-摆脱大量ListScroller

前言: 好久没写过文章了,最近在开发鸿蒙项目,于是乎想简单记录一下开发过程中遇到的一些好玩的东西或者经常会遇到的功能开发。

开发过程中经常遇到需要做可以上下左右滑动的类型的表格的实现,写之前也在华为论坛搜索了下相关的,官方文档提供了一种方案,创建了大量的ListScroller,个人感觉数据量大了就不是很好用,这里提供一种自己实现的方案

鉴于这个功能难度不是很大,仅仅就是布局和联动的实现,所以代码很少

效果

废话不多说,先上效果

布局

根据表格滑动的结构,可以看到布局结构如下,分别是横向滑动的标题,横向滑动的内容和上下滑动的标题+内容。

完整代码如下

ts 复制代码
@Entry
@ComponentV2
struct Index {
  leftWidth: number = 140
  cellWidth: number = 120
  cellHeight: number = 60
  titleHeight: number = 50
  private titleScroller: Scroller = new Scroller()
  private contentScroller: Scroller = new Scroller()
  private leftScroller: Scroller = new Scroller()
  private rightScroller: Scroller = new Scroller()
  titleList: string[] = []
  leftData: string[] = []
  rightData: string[] = []

  aboutToAppear(): void {
    for (let index = 0; index < 20; index++) {
      this.titleList.push(`标题${index}`)
    }
    for (let index = 0; index < 100; index++) {
      this.leftData.push(`左侧${index}`)
      this.rightData.push(`右侧行${index}`)
    }

  }

  build() {
    Column() {
      Row() {
        Text('标题').width(this.leftWidth).height(this.titleHeight).padding({ left: 16 })
        Scroll(this.titleScroller) {
          Row() {
            ForEach(this.titleList, (item: string) => {
              Text(item).width(this.cellWidth).height(this.titleHeight)
            })
          }
        }
        .layoutWeight(1)
        .scrollBar(BarState.Off)
        .edgeEffect(EdgeEffect.None)
        .scrollable(ScrollDirection.Horizontal)
        .onScrollFrameBegin((offset: number) => {
          this.contentScroller.scrollTo({
            xOffset: this.titleScroller.currentOffset().xOffset + offset,
            yOffset: 0,
            animation: false
          })
          return { offsetRemain: offset }
        })
      }.height(this.titleHeight)

      Column() {
        Row() {
          List({ scroller: this.leftScroller }) {
            Repeat<ESObject>(this.leftData).virtualScroll().each((ri: RepeatItem<ESObject>) => {
              ListItem() {
                Text(ri.item)
              }
              .height(this.cellHeight)
              .width(this.leftWidth)
              .itemBorder()
              .align(Alignment.Start)
              .padding({ left: 16 })
            })
            ListItem().height(this.cellHeight)
          }
          .width(this.leftWidth)
          .enableScrollInteraction(true)
          .scrollBar(BarState.Off)
          .edgeEffect(EdgeEffect.None)
          .cachedCount(20)
          .onScrollFrameBegin((offset: number) => {
            this.rightScroller.scrollTo({
              xOffset: 0,
              yOffset: this.leftScroller.currentOffset().yOffset + offset,
              animation: false
            })
            return ({ offsetRemain: offset })
          })

          Column() {
            Scroll(this.contentScroller) {
              List({ scroller: this.rightScroller }) {
                Repeat<string>(this.rightData).virtualScroll().each((ri: RepeatItem<ESObject>) => {
                  ListItem() {
                    Row() {
                      ForEach(this.titleList, (item: string, index: number) => {
                        Text(`${ri.item}列${index}`).width(this.cellWidth).height(this.cellHeight)
                      })
                    }
                  }.height(this.cellHeight).itemBorder()
                })
                ListItem().height(this.cellHeight)
              }
              .cachedCount(20)
              .enableScrollInteraction(true)
              .scrollBar(BarState.Off)
              .edgeEffect(EdgeEffect.None)
              .onScrollFrameBegin((offset: number) => {
                this.leftScroller.scrollTo({
                  xOffset: 0,
                  yOffset: this.rightScroller.currentOffset().yOffset + offset,
                  animation: false
                })
                return ({ offsetRemain: offset })
              })

            }
            .scrollBar(BarState.Off)
            .edgeEffect(EdgeEffect.None)
            .scrollable(ScrollDirection.Horizontal)
            .onScrollFrameBegin((offset: number) => {
              if (!this.contentScroller.isAtEnd()) {
                this.titleScroller.scrollTo({
                  xOffset: this.contentScroller.currentOffset().xOffset + offset,
                  yOffset: 0,
                  animation: false
                })
              }
              return { offsetRemain: offset }
            })
          }.layoutWeight(1)
        }
      }
    }
    .height('100%')
    .width('100%')
  }
}

@Styles
function itemBorder() {
  .border({
    color: '#cccccc',
    width: {
      left: 0,
      top: 0,
      right: 0,
      bottom: 1
    }
  })
}
相关推荐
想睡八个小时18 小时前
已包含的文件名 “a.vue“ 仅大小写与文件名 “A.vue“ 不同
前端·vscode
HONG````19 小时前
鸿蒙Tabs组件深度实战:构建流畅的多页面导航与状态保持方案
华为·harmonyos
ZWaruler19 小时前
鸿蒙os 配置打包后的文件名称
华为·harmonyos·鸿蒙系统
The_era_achievs_hero19 小时前
Echarts
前端·javascript·echarts
Devil枫19 小时前
[鸿蒙2025领航者闯关]从小白到鸿蒙星炬手
华为·harmonyos
涔溪20 小时前
Vite 和 Webpack 这两款主流前端构建工具的核心区别,包括它们的设计理念、工作机制和实际使用体验上的差异。
前端·webpack·vite
0思必得020 小时前
[Web自动化] 开发者工具元素(Elements)面板
运维·前端·自动化·web自动化·开发者工具
遇到困难睡大觉哈哈20 小时前
Harmony os ——ArkTS 语言笔记(五):泛型、空安全与可选链
前端·笔记·安全·harmonyos·鸿蒙
八哥程序员21 小时前
你真的理解了 javascript 中的原型及原型链?
前端·javascript
冴羽21 小时前
10 个 Nano Banana Pro 专业级生图技巧
前端·人工智能·aigc