
摘要
在当今移动端开发中,瀑布流布局已经成为图像展示、商品推荐、内容流推送等界面设计的"标配"。它能实现错落有致、不规则高宽度的排布形式,既美观又高效。而在 HarmonyOS 的 ArkUI 框架中,虽然没有直接命名为"瀑布流"的组件,但我们可以巧妙地使用 Grid
组件加上不定高的 item 来灵活实现这一布局。本文将从 ArkUI 的组件原理出发,带你搭建一个完整的瀑布流布局页面,覆盖实战 Demo、多个场景案例、动态列数适配、性能优化技巧等内容,帮助你快速掌握并落地这一常见界面需求。
引言:瀑布流为什么受欢迎?
如果你刷过小红书、看过 Pinterest、逛过淘宝推荐页,就一定见过瀑布流。它的最大特点是每个 item 高度不同,但能自动依列往下补位,形成流动性很强的错落排布效果。
相比传统的网格布局(Grid Layout)或线性列表(ListView),瀑布流具备:
- 视觉流动感强:非规则的高度组合形成自然流动效果;
- 空间利用率高:不会因为固定行高而造成空白;
- 适应图文信息流:特别适合封面图+标题、短视频卡片、商品瀑布推荐等。
ArkUI 中的 Grid:不是瀑布流,但可以变成瀑布流
基础结构:Grid 是如何工作的?
ArkUI 的 Grid
组件是一个典型的二维网格结构,你可以为其指定列数 columns
,每行会自动塞满元素,每个 itemBuilder
构建的组件会根据其内容自动调整大小。
ts
Grid({
columns: 2,
data: this.items,
itemBuilder: (item) => {
return Box().width('90%').height(150).backgroundColor(item);
}
})
重点在于:只要你每个 item 的高度不同,Grid 就会呈现瀑布效果。
ArkUI 不像 CSS 有 Masonry 怎么办?
确实,ArkUI 没有 masonry
、flex-wrap
、position: absolute
等 CSS 手段,但它提供了类似的"列优先"渲染逻辑,你可以通过:
- 手动设置 item 不同高度;
- 控制列数来影响排布密度;
- 利用
Flex
或Column
组合组件构造多样内容;
从而达到同样视觉效果。
从零开始构建瀑布流布局
Demo:构造一个彩色瀑布格子页
ts
@Entry
@Component
struct WaterfallFlowExample {
private items: string[] = Array.from({ length: 30 }, (_, i) => `#${Math.floor(Math.random() * 0xffffff).toString(16)}`);
build() {
Column() {
Text('ArkUI 瀑布流示例')
.fontSize(22)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 10 })
.align(Alignment.Center);
Grid({
columns: 2,
data: this.items,
itemBuilder: (item) => {
let height = 100 + Math.floor(Math.random() * 100); // 随机高度
return Box()
.width('90%')
.height(height)
.backgroundColor(item)
.borderRadius(12)
.margin(10)
.align(Alignment.Center);
}
}).width('100%');
}
}
}
代码说明
组件 | 作用 |
---|---|
Grid(columns: 2) |
设置两列排布 |
itemBuilder |
动态渲染每个 item,传入的 item 为颜色值 |
height = 100 + 随机 |
随机高度形成不规则视觉 |
Box() |
内容容器,设置背景色和大小 |
提示: 这里的随机高度模拟的是实际场景中,比如商品卡片图片、视频封面、图文摘要块内容高度不同的情况。
实际场景应用案例
电商类:商品卡片流展示
瀑布流最常见的应用之一就是商品推荐,比如淘宝首页、京东发现频道。每个商品高度不同(因图片或描述),用瀑布流可以最大程度利用屏幕空间。
示例代码
ts
let productList = [
{ name: 'T恤', price: '¥59', color: '#ffe4e1', height: 180 },
{ name: '牛仔裤', price: '¥128', color: '#e0ffff', height: 220 },
{ name: '运动鞋', price: '¥289', color: '#f0e68c', height: 160 },
// ...可扩展更多商品
];
Grid({
columns: 2,
data: productList,
itemBuilder: (item) => {
return Column()
.width('90%')
.height(item.height)
.backgroundColor(item.color)
.borderRadius(12)
.padding(10)
.margin(8)
.justifyContent(FlexAlign.SpaceBetween)
.align(Alignment.Center)
.children([
Text(item.name).fontSize(16).fontWeight(FontWeight.Medium),
Text(item.price).fontSize(14).fontColor(Color.Red)
]);
}
}).width('100%');
图文信息流 / 社交推荐流
你也可以封装内容卡片组件,用于推荐文章、小视频、短图文等。如下为封装示例:
ts
@Component
struct ContentCard {
@Prop item: { title: string; desc: string; color: string; height: number };
build() {
Column()
.width('90%')
.height(this.item.height)
.backgroundColor(this.item.color)
.padding(10)
.borderRadius(10)
.children([
Text(this.item.title).fontSize(18).fontWeight(FontWeight.Bold),
Text(this.item.desc).fontSize(14).margin({ top: 6 })
]);
}
}
然后在主布局中:
ts
Grid({
columns: 2,
data: articleList,
itemBuilder: (item) => {
return ContentCard({ item });
}
});
实战技巧进阶篇
动态列数适配设备宽度
通过屏幕宽度判断列数,实现响应式布局:
ts
let deviceWidth = device.screenWidth;
let columns = deviceWidth > 800 ? 3 : 2;
Grid({
columns: columns,
data: this.items,
itemBuilder: ...
});
Scroll 配合懒加载(分页)
ArkUI 的 Scroll
可以配合加载更多按钮或滑动到底触发加载:
ts
Scroll() {
Grid({
columns: 2,
data: this.items,
itemBuilder: ...
});
Button("加载更多")
.onClick(() => this.loadMore());
}
开发者常见问题解答
Q1:ArkUI 为什么不提供内置瀑布流组件?
ArkUI 是一个偏低层的 UI 框架,它提供的是通用的布局组件,而不是封装复杂行为的高阶组件。这样反而更灵活,我们可以自由控制样式、行为和性能。
Q2:Grid 布局时 item 不对齐怎么办?
确保你:
- 设置了统一
Box().width('90%')
- 控制好
margin
值 - 外层容器
.width('100%')
这样每列对齐不会错位。
Q3:每个 item 高度不一会不会影响性能?
不会太大影响,ArkUI 的渲染逻辑是分块计算的。只要你 item 数量不过多(<1000),或结合分页处理,性能基本没有问题。
总结:借力 Grid,ArkUI 也能"瀑"得漂亮!
本文通过多个维度深入讲解了 ArkUI 中如何实现瀑布流布局。虽然没有现成组件,但借助 Grid
与自定义 item 高度,我们完全可以打造出高性能、易扩展的瀑布流效果。你可以自由调整列数、高度、内容结构,配合封装的组件、分页加载等逻辑,实现适用于图文、电商、社交等多种 App 场景的通用 UI 模板。
重点回顾:
- 利用
Grid(columns: n)
设置列数; - 每个
itemBuilder
设置不同高度,即可模拟瀑布流; - 结合
Scroll
、分页、动态列数可做成完整内容流; - 场景涵盖商品展示、文章推荐、图文封面流等;
未来你也可以将这套布局封装为自定义组件,作为团队项目的 UI 模板进行复用,提高开发效率。