HarmonyOS鸿蒙Next中如何实现表格布局?

HarmonyOS鸿蒙Next中如何实现表格布局? 表格支持上下左右均可滚动。

3 回复

预览效果:

cke_642.gif

实现思路:

1、先将布局分为左右两个布局,左边使用List,右边使用Scroll+List

2、左右两边的表头使用 Group的header实现,右边的header是一个横向的List,并且设置不可滚动。

3、右边表的每一行都使用一个横向List实现,并且设置不可滚动。

4、右边表的横向滚动都交给Scroll来处理。

5、左右两边的List都需要把回弹效果关掉,避免滚动时两边不同步。

PS:demo演示使用的是ForEach,实际项目推荐使用LazyForEach以提升性能。

完整的demo:

/**
 * @fileName : Table.ets
 * @author : @cxy
 * @date : 2025/12/22
 * @description : 实现左右上下都可滑动的表格
 */

@Component
export struct Table {
  @State titles: string[] = []
  @State leftList: string[] = []
  @State rightList: string[][] = []
  private leftScroller: ListScroller = new ListScroller()
  private rightScroller: ListScroller = new ListScroller()

  aboutToAppear(): void {
    const leftList: string[] = []
    const rightList: string[][] = []

    for (let i = 0; i < 30; i++) {
      leftList.push((i + 1).toString())
      const items: string[] = []
      for (let j = 0; j < 10; j++) {
        items.push(`${i + 1},${j + 1}`)
      }
      rightList.push(items)
    }

    this.leftList = leftList
    this.rightList = rightList

    for (let j = 0; j < 10; j++) {
      this.titles.push(`列${j + 1}`)
    }
  }

  build() {
    Column() {
      Row() {
        this.leftBuilder()
        this.rightBuilder()
      }
      .alignItems(VerticalAlign.Center)
      .width('100%')
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  leftBuilder() {
    List({ scroller: this.leftScroller }) {
      ListItemGroup({ header: this.leftHeader() }) {
        // 通常需要使用 LazyForEach 提升性能
        ForEach(this.leftList, (item: string, index: number) => {
          ListItem() {
            Text(item)
              .height('100%')
              .width('100%')
              .textAlign(TextAlign.Center)
          }
          .height(40)
          .width('100%')
          .backgroundColor(index % 2 === 0 ? '#fff' : '#f0f0f0')
        }, (item: string) => item)
      }
    }
    .sticky(StickyStyle.Header)
    .width(50)
    .height('100%')
    .scrollBar(BarState.Off)
    .edgeEffect(EdgeEffect.None)
    .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
      if (scrollState !== ScrollState.Idle) {
        this.rightScroller.scrollTo({
          xOffset: 0,
          yOffset: this.leftScroller.currentOffset().yOffset
        })
      }
    })
  }

  @Builder
  leftHeader() {
    Text('序号')
      .textAlign(TextAlign.Center)
      .height(40)
      .width(50)
      .backgroundColor('#ccc')
  }

  @Builder
  rightBuilder() {
    Scroll() {
      List({ scroller: this.rightScroller }) {
        ListItemGroup({ header: this.rightHeader() }) {
          // 通常需要使用 LazyForEach 提升性能
          ForEach(this.rightList, (item: string[], index: number) => {
            ListItem() {
              this.rightListItem(item)
            }
            .height(40)
            .width('100%')
            .backgroundColor(index % 2 === 0 ? '#fff' : '#f0f0f0')
          }, (item: string) => item)
        }
      }
      .sticky(StickyStyle.Header)
      .width(10 * 100)
      .height('100%')
      .edgeEffect(EdgeEffect.None)
      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
        if (scrollState !== ScrollState.Idle) {
          this.leftScroller.scrollTo({
            xOffset: 0,
            yOffset: this.rightScroller.currentOffset().yOffset
          })
        }
      })
    }
    .scrollable(ScrollDirection.Horizontal)
    .align(Alignment.TopStart)
    .height('100%')
    .layoutWeight(1)
  }

  @Builder
  rightListItem(items: string[]) {
    List() {
      ForEach(items, (item: string, index: number) => {
        ListItem() {
          Text(item)
            .height('100%')
            .width('100%')
            .textAlign(TextAlign.Center)
        }
        .width(100)
      }, (item: string) => item)
    }
    .height('100%')
    .width('100%')
    .listDirection(Axis.Horizontal)
    .scrollBar(BarState.Off)
    .edgeEffect(EdgeEffect.None)
    .enableScrollInteraction(false)
  }

  @Builder
  rightHeader() {
    List() {
      ForEach(this.titles, (item: string, index: number) => {
        ListItem() {
          Text(item)
            .height('100%')
            .width('100%')
            .textAlign(TextAlign.Center)
        }
        .width(100)
      }, (item: string) => item)
    }
    .backgroundColor('#ccc')
    .height(40)
    .width(this.titles.length * 100)
    .listDirection(Axis.Horizontal)
    .scrollBar(BarState.Off)
    .edgeEffect(EdgeEffect.None)
    .enableScrollInteraction(false)
  }
}

更多关于HarmonyOS鸿蒙Next中如何实现表格布局?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,可通过TableContainer组件实现表格布局。该组件以行和列的形式排列子组件,支持设置行数和列数,并自动管理单元格大小。开发者需在TableContainer内添加子组件,系统会按顺序将其填充至表格单元格中。布局方式简洁,适用于规整的数据展示界面。

在HarmonyOS Next中,可以通过GridContainer组件实现支持上下左右滚动的表格布局。

核心实现步骤:

  1. 使用GridContainer:作为表格的容器,设置滚动方向为双向
GridContainer() {
  // 表格内容
}
.scrollable(ScrollDirection.Horizontal | ScrollDirection.Vertical) // 启用双向滚动
  1. 定义表格结构:结合GridRow和GridCol构建行列
GridRow() {
  // 表头
  GridCol({ span: { xs: 12 } }) {
    // 表头内容
  }
  
  // 表格数据行
  ForEach(data, item => {
    GridCol({ span: { xs: 12 } }) {
      // 每行数据
    }
  })
}
  1. 关键配置
  • 设置columnsTemplate定义列宽比例
  • 使用constraintSize控制表格尺寸
  • 通过layoutWeight实现自适应布局
  1. 性能优化:对于大数据量表格,建议使用LazyForEach延迟加载行数据,避免一次性渲染所有行造成的性能问题。

这种实现方式既保持了表格的结构化特性,又通过双向滚动提供了灵活的数据展示空间。

回到顶部