Grid 双栏网格与 List 单栏列表的视图切换实现
2026/7/19 1:22:44 网站建设 项目流程

前言

在内容型应用中,视图切换是提升用户体验的重要功能。用户可以根据自己的偏好选择网格浏览或列表浏览。“海风日记“的首页支持双栏网格(Grid)和单栏列表(List)两种视图模式,通过右上角的切换按钮实现一键切换。

本文将从HomeTab.ets源码出发,深入讲解 Grid 和 List 组件的完整配置、视图切换的实现机制以及数据驱动渲染的最佳实践。


一、Grid 与 List 组件概述

1.1 Grid 组件

Grid 用于实现网格布局,支持自定义列数、行数和间距:

Grid() { ForEach(this.diaryList, (item: DiaryEntry) => { GridItem() { DiaryCard({ ... }) } }) } .columnsTemplate('1fr 1fr') // 双栏 .columnsGap(10) // 列间距 .rowsGap(10) // 行间距 .padding({ left: 12, right: 12 }) .layoutWeight(1)

1.2 List 组件

List 用于实现列表布局,支持垂直或水平滚动:

List({ space: 12 }) { ForEach(this.diaryList, (item: DiaryEntry) => { ListItem() { DiaryCard({ ... }) } }) } .padding({ left: 14, right: 14 }) .layoutWeight(1) .scrollBar(BarState.Off)

1.3 Grid 与 List 的对比

对比维度GridList
布局方式网格单列
显示密度高(一屏可展示更多内容)
适用场景图片为主、快速浏览文字为主、详细阅读
内容展示单行显示更多信息信息更完整

二、视图切换的实现

2.1 状态变量

@Component export struct HomeTab { @State isGridView: boolean = true // 当前视图模式 @State diaryList: DiaryEntry[] = MOCK_DIARIES // 日记数据 }

2.2 切换按钮

Button() { SymbolGlyph( this.isGridView ? $r('sys.symbol.square_grid_2x2') // 网格图标 : $r('sys.symbol.list_bullet') // 列表图标 ) .fontSize(18) .fontColor(['#C8956A']) } .width(30).height(30) .borderRadius(8) .backgroundColor('rgba(245,166,35,0.10)') .onClick(() => { this.isGridView = !this.isGridView })

2.3 条件渲染视图

if (this.isGridView) { // 双栏网格 Grid() { ForEach(this.diaryList, (item: DiaryEntry) => { GridItem() { DiaryCard({ ... }) } }) } .columnsTemplate('1fr 1fr') .columnsGap(10).rowsGap(10) .padding({ left: 12, right: 12, bottom: TAB_BAR_HEIGHT + 16 }) .layoutWeight(1) } else { // 单栏列表 List({ space: 12 }) { ForEach(this.diaryList, (item: DiaryEntry) => { ListItem() { DiaryCard({ ... }) } }) } .padding({ left: 14, right: 14, bottom: TAB_BAR_HEIGHT + 16 }) .layoutWeight(1) .scrollBar(BarState.Off) }

三、Grid 组件的属性详解

3.1 columnsTemplate

.columnsTemplate('1fr 1fr') // 两列,每列等宽

columnsTemplate使用 fr 单位来分配列宽:

模板效果
'1fr 1fr'两列等宽
'1fr 2fr'第二列宽度是第一列的两倍
'repeat(3, 1fr)'三列等宽

3.2 间距控制

.columnsGap(10) // 列间距 10vp .rowsGap(10) // 行间距 10vp

3.3 滚动控制

Grid 默认可滚动,无需额外配置。如果需要禁用滚动:

Grid() .scrollBar(BarState.Off) // 隐藏滚动条

四、List 组件的属性详解

4.1 间距

List({ space: 12 }) // 列表项间距 12vp

4.2 滚动条

List() .scrollBar(BarState.Off) // 隐藏滚动条 // 或 .scrollBar(BarState.Auto) // 自动显示 // 或 .scrollBar(BarState.On) // 始终显示

4.3 列表项

List() { ForEach(this.diaryList, (item: DiaryEntry) => { ListItem() { DiaryCard({ ... }) } }) }

五、视图切换的动画效果

5.1 使用 animateTo

.onClick(() => { animateTo({ duration: 300 }, () => { this.isGridView = !this.isGridView }) })

5.2 过渡动画

// 视图切换时添加过渡动画 Grid() .transition({ type: TransitionType.Insert, scale: { x: 0, y: 0 } }) .transition({ type: TransitionType.Delete, scale: { x: 0, y: 0 } })

六、数据驱动渲染

6.1 ForEach 的使用

ForEach( this.diaryList, // 数据源 (item: DiaryEntry) => { // UI 构建函数 GridItem() { DiaryCard({ ... }) } }, (item: DiaryEntry) => item.id // 键值生成函数 )

6.2 键值的重要性

键值用于标识列表项的唯一性,帮助 ArkUI 高效更新列表:

  • 键值必须是唯一的
  • 键值不建议使用数组索引
  • 建议使用数据 ID 作为键值

七、常见问题与排查

7.1 Grid 显示空白

问题:Grid 区域显示为空白。

原因:Grid 没有设置columnsTemplate,或数据源为空。

解决方案

Grid() .columnsTemplate('1fr 1fr') // 必须设置列模板

7.2 List 滚动条不消失

问题:设置了scrollBar(BarState.Off)但滚动条仍然显示。

原因:属性设置顺序错误。

解决方案:确保scrollBar在布局属性之后设置。


总结

本文通过“海风日记“首页的源码,深入讲解了 Grid 和 List 组件的完整用法:

  1. Grid 组件:双栏网格布局的配置
  2. List 组件:单栏列表布局的配置
  3. 视图切换:@State + 条件渲染实现一键切换
  4. 属性详解:columnsTemplate、间距、滚动条
  5. 动画效果:animateTo 和过渡动画
  6. 数据驱动:ForEach 的数据绑定和键值管理

下一篇文章将深入讲解ForEach 数据驱动渲染,敬请期待。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • Grid 组件文档
  • List 组件文档
  • ForEach 文档
  • 海风日记项目源码
  • [HarmonyOS 开发者官网](https://atomgit.com/openharmony/docs
  • 开源鸿蒙跨平台社区
  • ArkUI 动画概述
  • animateTo 动画

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询