#跟着若城学鸿蒙# UI组件篇-WaterFlow及其属性
·
一、WaterFlow 组件概述
WaterFlow(瀑布流)是 ArkUI 提供的一个高性能容器组件,专门用于实现瀑布流布局效果。它在购物、资讯类应用中尤为常见,能够高效展示大小不一的图片和内容区块。
1.1 基本特性
WaterFlow 组件具有以下核心特点:
- 动态布局:自动计算最优位置,使不同高度的项目紧密排列
- 高性能:支持懒加载、组件复用等优化手段
- 灵活布局:支持纵向和横向两种布局方向
- 无限滚动:便捷实现触底加载更多数据的功能
- 分组混合:支持不同分组使用不同列数的混合布局
1.2 核心优势
相比传统的 Grid 或 List 组件,WaterFlow 在以下方面表现更优:
- 不规则内容展示:完美适应高度不一的子项内容
- 视觉吸引力:错落有致的布局增强用户体验
- 内存优化:先进的回收机制降低内存消耗
- 开发便捷:内置复杂布局逻辑,开发者只需关注内容
二、WaterFlow 核心功能详解
2.1 基础布局方式
WaterFlow 支持两种基础布局模式:
// 纵向布局(默认) WaterFlow({ layoutMode: WaterFlowLayoutMode.ALWAYS_TOP_DOWN }) { // 子项 } .columnsTemplate('1fr 1fr 1fr') // 设置3列 // 横向布局 WaterFlow({ layoutMode: WaterFlowLayoutMode.ALWAYS_TOP_DOWN }) { // 子项 } .rowsTemplate('1fr 1fr') // 设置2行 .layoutDirection(FlexDirection.Row)
布局规则:
- 纵向布局:项目从左到右排列,新项目放置在当前高度最小的列
- 横向布局:项目从上到下排列,新项目放置在当前宽度最小的行
2.2 无限滚动实现
实现无限滚动需要结合 LazyForEach 和数据源管理:
@State
dataSource: WaterFlowDataSource = new WaterFlowDataSource(initialData)
build() {
WaterFlow({ footer: this.loadingFooter() }) {
LazyForEach(this.dataSource, (item: number) => {
FlowItem() { // 内容项
}.onAppear(() => {
// 触底预加载
if (item.index === this.dataSource.totalCount() - 5) {
this.loadMoreData()
}
})
})
}.onReachEnd(() => {
// 触底加载
this.loadMoreData()
})
}
private loadMoreData() {
// 模拟异步加载
setTimeout(() => {
this.dataSource.addNewItems(10)
}, 1000)
}
2.3 分组混合布局
WaterFlow 支持通过 WaterFlowSections 实现分组布局:
@State
sections: WaterFlowSections = new WaterFlowSections()
aboutToAppear() {
const headerSection: SectionOptions = {
itemsCount: 1, crossCount: 1,
// 单列
margin: {
top: 10,
left: 10,
right: 10,
bottom: 10
}
}
const contentSection: SectionOptions = {
itemsCount: 20,
crossCount: 2,
// 双列
columnsGap: 5,
rowsGap: 5
}
this.sections.splice(0, 0, [headerSection, contentSection])
}
build() {
WaterFlow({ sections: this.sections }) {
// 内容项
}
}
三、性能优化策略
3.1 组件复用
使用 @Reusable 装饰器实现组件复用:
@Reusable @Component struct ReusableItem { @Prop item: ItemData aboutToReuse(params: Record<string, any>) { this.item = params.item } build() { // 组件布局 } }
3.2 懒加载优化
结合 LazyForEach 和 NodeAdapter 实现高效懒加载:
// ArkTS 示例 WaterFlow() { LazyForEach(this.dataSource, (item) => { FlowItem() { ReusableItem({ item }) } }) } // NDK 示例 class FlowItemAdapter { private adapter: ArkUI_NodeAdapterHandle constructor() { this.adapter = OH_ArkUI_NodeAdapter_Create() OH_ArkUI_NodeAdapter_SetEventCallback(this.adapter, this.onAdapterEvent) } private onAdapterEvent(event: ArkUI_NodeAdapterEvent) { // 处理创建、复用、销毁逻辑 } }
3.3 预加载机制
通过 Prefetcher 实现数据预取:
class MyPrefetcher implements IPrefetcher { private dataSource?: IDataSourcePrefetching setDataSource(dataSource: IDataSourcePrefetching): void { this.dataSource = dataSource } visibleAreaChanged(minVisible: number, maxVisible: number): void { this.dataSource?.prefetch(minVisible - 5, maxVisible + 5) } } // 使用 const prefetcher = new MyPrefetcher() WaterFlow() .prefetcher(prefetcher)
四、高级功能探索
4.1 动态列数调整
@State columns: number = 2 build() { Column() { Button('切换列数') .onClick(() => { this.columns = this.columns === 2 ? 3 : 2 }) WaterFlow() { // 内容 } .columnsTemplate(`1fr `.repeat(this.columns)) } }
4.2 嵌套滚动处理
WaterFlow() .nestedScroll({ scrollForward: NestedScrollMode.PARENT_FIRST, // 向前滚动父组件优先 scrollBackward: NestedScrollMode.SELF_FIRST // 向后滚动自身优先 })
4.3 自定义滚动条
WaterFlow() .scrollBar(BarState.On) .scrollBarWidth(10) .scrollBarColor(Color.Gray)
五、实战案例分析
5.1 电商商品列表实现
@Entry
@Component
struct ShoppingPage {
@State products: Product[] = []
@State loading: boolean = false
build() {
Column() {
WaterFlow({ footer: this.loading ? this.loadingIndicator() : null }) {
LazyForEach(new ArrayDataSource(this.products), (product: Product) => {
FlowItem() {
ProductItem({ product })
}
})
}.columnsTemplate('1fr 1fr').onReachEnd(() => this.loadMore())
}
}
private loadMore() {
if (this.loading) {
return this.loading = true
}
fetchProducts().then(newProducts => {
this.products.push(...newProducts)
this.loading = false
})
}
}
5.2 图片社交应用
@Entry
@Component
struct SocialGallery {
@State posts: SocialPost[] = []
@State currentIndex: number = 0
build() {
WaterFlow({ layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) {
LazyForEach(new ArrayDataSource(this.posts), (post: SocialPost) => {
FlowItem() {
PostCard({ post })
}.onAppear(() => {
// 预加载附近项
if (post.index - this.currentIndex < 5) {
prefetchPost(post.id + 1)
}
})
})
}.onScrollIndex((first, last) => {
this.currentIndex = first
})
}
}
六、常见问题解决方案
6.1 白屏问题处理
问题现象:快速滑动时出现空白区域
解决方案:
- 增加 prefetch 预加载范围
- 使用固定尺寸替代自适应高度
- 添加合适的占位组件
FlowItem() { Column() { // 图片加载前显示占位 if (this.imageLoaded) { Image(this.imageUrl) } else { Placeholder() .onAppear(() => loadImage()) } } } .width('100%') .height(200) // 固定高度
6.2 内存优化
优化策略:
- 限制缓存数量
- 及时释放资源
- 使用低分辨率预览图
WaterFlow() .cachedCount(10) // 限制缓存数量
6.3 性能监测
WaterFlow() .onScrollIndex((first, last) => { Logger.info(`Visible items: ${first} - ${last}`) PerformanceTrace.trace('WaterFlow scrolling') })
----
以上
更多推荐


所有评论(0)