为文章《HarmonyOS7 水流布局适合内容卡片流:别把瀑布流当九宫格用》生成一张手绘笔记风的信息

前言

图片社区、笔记流、菜谱卡片这类页面,用普通两列 Grid 经常会出现大块空白。原因很简单:每张卡片高度不一样,硬凑整齐反而浪费屏幕。

HarmonyOS7 里可以用 WaterFlow 承载这种内容流。我的判断是:内容高度天然不一致,用户又是连续浏览,就可以考虑水流布局。如果每个入口都是同等权重,比如功能菜单、分类入口,那就不要用它。

为什么这个问题经常被写乱

水流布局适合内容卡片流 这类内容很容易被写成“代码能跑就算讲完了”,但对初学者来说,这恰恰是最不够的地方。真正让人卡住的,往往不是某个组件名记不住,而是不知道这段代码为什么要这样拆、状态为什么要这样放、以后需求变化时应该从哪里改。

所以这篇文章不只想给你一个能跑的例子,更想把背后的判断过程讲清楚。你只要把这个判断过程吃透,后面自己改页面、补需求、查问题时,心里会稳很多。

适用场景要先分清

WaterFlow 不是“更高级的 Grid”。它解决的是不等高内容的浏览效率。

为文章中的“适用场景要先分清”部分生成一张手绘流程图。内容从“页面要展示什么”开始,分支判断:1)内

场景 是否推荐 原因
图片笔记流 推荐 图片比例和文字长度不同
商品瀑布流 推荐 卡片信息密度差异明显
设置菜单 不推荐 条目应该稳定、可预测
分类入口 不推荐 用户需要快速扫固定位置

为文章中“瀑布流的重点在数据准备”部分生成一张手绘信息图,主题是 WaterFlow 卡片数据准备清

如果用户的目标是“找到一个固定入口”,瀑布流会让位置变得不稳定。如果用户的目标是“连续浏览内容”,水流布局才有价值。

瀑布流的重点在数据准备

瀑布流最容易翻车的地方不是 API,而是图片高度。图片真实高度、标题行数、作者信息、互动数都会影响卡片最终高度。

数据字段 用途
id 作为稳定 key
imageHeight 提前占位,减少加载跳动
title 限制最多两行
topic 用于图片占位或标签展示
likes 作为轻量互动信息

真实项目里,最好让服务端返回图片宽高,前端按比例换算显示高度。示例里直接使用 imageHeight,就是为了把“先有占位高度”这件事讲清楚。

ArkUI/ArkTS 完整示例

interface FeedCard44 {
  id: number
  title: string
  author: string
  imageHeight: number
  likes: number
  topic: string
}

@Entry
@Component
struct ContentWaterFlowPage {
  @State selectedTitle: string = '还没有打开卡片'
  private cards: FeedCard44[] = [
    { id: 1, title: '周末徒步路线记录', author: '阿宁', imageHeight: 156, likes: 82, topic: '户外' },
    { id: 2, title: '三步整理桌面小技巧', author: '林木', imageHeight: 110, likes: 41, topic: '整理' },
    { id: 3, title: '咖啡豆手冲参数', author: '小北', imageHeight: 186, likes: 128, topic: '咖啡' },
    { id: 4, title: 'HarmonyOS7 卡片布局练习', author: '程同学', imageHeight: 132, likes: 66, topic: '开发' }
  ]

  @Builder
  FeedCard(item: FeedCard44) {
    Column({ space: 8 }) {
      Stack() {
        Text(item.topic)
          .fontSize(14)
          .fontColor('#777777')
      }
      .height(item.imageHeight)
      .width('100%')
      .backgroundColor('#DDE7F8')
      .borderRadius(8)

      Text(item.title)
        .fontSize(15)
        .fontWeight(FontWeight.Medium)
        .maxLines(2)
        .textOverflow({ overflow: TextOverflow.Ellipsis })

      Row() {
        Text(item.author).fontSize(12).fontColor('#777777')
        Blank()
        Text(`${item.likes}`).fontSize(12).fontColor('#777777')
      }
    }
    .padding(10)
    .backgroundColor(Color.White)
    .borderRadius(8)
    .onClick(() => {
      this.selectedTitle = item.title
    })
  }

  build() {
    Column({ space: 12 }) {
      Text('内容流')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .width('100%')

      Text(this.selectedTitle)
        .fontSize(13)
        .fontColor('#0A59F7')
        .width('100%')

      WaterFlow() {
        ForEach(this.cards, (item: FeedCard44) => {
          FlowItem() {
            this.FeedCard(item)
          }
        }, (item: FeedCard44) => item.id.toString())
      }
      .columnsTemplate('1fr 1fr')
      .columnsGap(12)
      .rowsGap(12)
      .layoutWeight(1)
    }
    .padding(16)
    .height('100%')
    .backgroundColor('#F5F7FA')
  }
}

把关键代码一段段拆开

imageHeight 提前进入模型。 即使真实项目使用网络图片,也尽量提前拿到宽高。否则图片加载前后高度变化,会让用户正在看的卡片跳走。

FlowItem 只包一张卡片。 水流布局已经负责排布,卡片内部不要再塞复杂 Grid。结构越重,后续越难处理点击、曝光和懒加载。

.columnsTemplate('1fr 1fr') 是列策略入口。 手机两列比较常见,平板可以扩展成三列或四列,但不要在内容卡片里写死宽度。

列数和卡片高度怎么定

设备/内容 推荐列数 说明
手机图片笔记 2 列 信息密度和可读性比较平衡
折叠屏展开态 3 列 内容更多,但文字仍要限行
平板横屏 3 到 4 列 需要配合最大内容宽度
纯文字卡片 不一定用 WaterFlow 高度差异不大时普通列表更稳

卡片标题最好限制行数。瀑布流允许高度不同,但不代表单张卡片可以无限拉长。标题、图片、互动区都要有边界,浏览节奏才不会散。

常见坑

  1. 图片加载后才决定高度。 页面会跳动,用户正在看的内容可能被挤走。
  2. 标题不限制行数。 长标题会把单张卡片拉得过长,破坏流式节奏。
  3. 把瀑布流当功能入口。 入口类页面需要固定位置,不适合自然流。
  4. 卡片里嵌复杂交互。 收藏、关注、长按菜单都可以做,但触摸区域要分清,避免误触详情。

小结

水流布局适合“内容自己决定高度”的页面。HarmonyOS7 里写 WaterFlow 时,别先纠结样式,先把数据高度、稳定 key、点击反馈处理好,页面就不会散。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐