HarmonyOS6 - WaterFlow瀑布流容器案例

HarmonyOS6 - WaterFlow瀑布流容器案例

开发环境为:

开发工具:DevEco Studio 6.0.1 Release

API版本是:API21

本文所有代码都已使用模拟器测试成功!

1. WaterFlow介绍

瀑布流容器,由"行"和"列"分割的单元格所组成,通过容器自身的排列规则,将不同大小的"项目"自上而下,如瀑布般紧密布局。

注意:

  • 仅支持FlowItem子组件和自定义组件。
  • 自定义组件在WaterFlow下使用时,建议使用FlowItem作为自定组件的顶层组件,不建议给自定义组件设置属性和事件方法。
  • 支持通过渲染控制类型(if/elseForEachLazyForEachRepeat)动态生成子组件,更推荐使用LazyForEach或Repeat以优化性能。
  • WaterFlow子组件的visibility属性设置为None时不显示,但该子组件周围的columnsGap、rowsGap、margin仍会生效。
  • 在涉及大量子组件的情况下,建议采用懒加载、缓存数据、组件复用、固定宽高以及布局优化等方法,以提升性能和减少内存占用。
  • 纵向布局时,WaterFlow会计算每一列中已放置子组件的累计高度,并将新子组件放入累计高度最小的那一列,以保持整体布局紧凑。
  • 若多个列的高度相同,优先放入最左边的列。在RTL模式下,优先放入最右边的列。
  • 从API version 21开始,WaterFlow单个子组件的宽高最大为16777216px;API version 20及之前,WaterFlow单个子组件的宽高最大为1000000px。子组件超出该大小可能导致滚动或显示异常。

官网文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-waterflow

2. 案例

1. 效果

效果图如下:

2. 代码

代码如下:

js 复制代码
import CommonConstants from '../common/CommonConstants'
import { CardModel } from '../model/CardModel';
import { WaterFlowDataSource } from '../model/WaterFlowDataSource';

/**
 * Desc: 社区
 * Author: 波波老师(weixin: javabobo0513)
 */
@Entry
@Component
export struct Page002 {
  @StorageProp('bottomRectHeight')
  bottomRectHeight: number = 0;
  @StorageProp('topRectHeight')
  topRectHeight: number = 0;
  @State listData: Array<CardModel> = [
    new CardModel($r('app.media.c1'), '社区老年人活动游戏', $r('app.media.user_1003'), '刘小太太', '4586'),
    new CardModel($r('app.media.c2'), '社区组织的剪纸活动', $r('app.media.user_1004'), '一颗红心', '2635'),
    new CardModel($r('app.media.c3'), '社区走访独居老人', $r('app.media.user_1006'), '牡丹花心', '2369'),
    new CardModel($r('app.media.c4'), '人间群像「空巢老人的聚会」', $r('app.media.user_1007'), '奔跑的玫瑰', '3018'),
    new CardModel($r('app.media.c1'), '社区老年人活动游戏', $r('app.media.user_1003'), '刘小太太', '4586'),
    new CardModel($r('app.media.c2'), '社区组织的剪纸活动', $r('app.media.user_1004'), '一颗红心', '2635'),
    new CardModel($r('app.media.c3'), '社区走访独居老人', $r('app.media.user_1006'), '牡丹花心', '2369'),
    new CardModel($r('app.media.c4'), '人间群像「空巢老人的聚会」', $r('app.media.user_1007'), '奔跑的玫瑰', '3018'),
  ]
  @State dataSource: WaterFlowDataSource = new WaterFlowDataSource();
  scroller: Scroller = new Scroller();

  aboutToAppear(): void {
    this.dataSource.addDataItem(this.listData);
  }

  build() {
    Column() {

      //头部标题
      Row() {
        Text('社区')
          .fontSize(20)
          .fontWeight(800)
      }
      .width('100%')
      .justifyContent(FlexAlign.Center)
      .margin({ bottom: 5 })


      //内容区域
      Scroll() {
        Column() {

          WaterFlow({ scroller: this.scroller }) {
            LazyForEach(this.dataSource, (item: CardModel) => {
              FlowItem() {
                Column({ space: 7 }) {
                  Image(item.img)
                    .borderRadius(8)
                    .width('100%')
                  Text(item.title)
                    .fontSize(15)
                  Row() {
                    Row({ space: 3 }) {
                      Image(item.userImg)
                        .borderRadius(50)
                        .width(18)
                      Text(item.userName)
                        .fontSize(11)
                    }

                    Row({ space: 3 }) {
                      Image($r('app.media.svg_like'))
                        .fillColor('#ff8d8d8d')
                        .width(18)
                      Text(item.likeCount)
                        .fontSize(11)
                    }
                  }
                  .width('100%')
                  .justifyContent(FlexAlign.SpaceBetween)
                }
                .width('100%')
                .alignItems(HorizontalAlign.Start)
              }
              .width('100%')
              .backgroundColor('#ffffff')
            })
          }
          .columnsTemplate('1fr 1fr') //设置当前瀑布流组件布局列的数量,不设置时默认1列
          .columnsGap(12) //设置列与列的间距。
          .rowsGap(15) //设置行与行的间距。
          .height('90%')
          // 单边边缘效果:设置弹簧效果,仅在顶部生效
          // EdgeEffect.Spring:弹簧回弹效果,滑动到边界时会有弹性回弹
          // alwaysEnabled: true:始终启用边缘效果,即使内容不足以滚动
          // effectEdge: EffectEdge.START:仅在起始边缘(顶部)生效
          // 效果:只有向上滑动到顶部时才会有弹簧回弹效果,向下滑动到底部不会有效果
          .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true, effectEdge: EffectEdge.START })
        }
        .width('100%')
      }
      .scrollable(ScrollDirection.Vertical) // 滚动方向纵向
      .scrollBar(BarState.Off) // 设置滚动条隐藏
      .edgeEffect(EdgeEffect.Fade) //设置滑动效果
      .align(Alignment.Top) //内容顶部对齐
      .height('100%') //设置高度


    }
    .width('100%')
    .height('100%')
    // top数值与状态栏区域高度保持一致;bottom数值与导航区域高度保持一致
    .padding({
      top: this.getUIContext().px2vp(this.topRectHeight),
      bottom: this.getUIContext().px2vp(this.bottomRectHeight),
      left: CommonConstants.LEFT_PADDING,
      right: CommonConstants.RIGHT_PADDING
    })
  }
}

WaterFlowDataSource代码如下:

js 复制代码
import { CardModel } from "./CardModel";

/**
 * 实现IDataSource接口的对象,用于瀑布流组件加载数据
 */
export class WaterFlowDataSource implements IDataSource {
  private dataArray: CardModel[] = [];
  private listeners: DataChangeListener[] = [];

  // 获取索引对应的数据
  public getData(index: number): CardModel {
    return this.dataArray[index];
  }

  // 通知控制器数据重新加载
  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded();
    })
  }

  // 通知控制器数据增加
  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
    })
  }

  // 通知控制器数据变化
  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataChange(index);
    })
  }

  // 通知控制器数据删除
  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataDelete(index);
    })
  }

  // 通知控制器数据位置变化
  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to);
    })
  }

  //通知控制器数据批量修改
  notifyDatasetChange(operations: DataOperation[]): void {
    this.listeners.forEach(listener => {
      listener.onDatasetChange(operations);
    })
  }

  // 获取数据总数
  public totalCount(): number {
    return this.dataArray.length;
  }

  // 注册改变数据的控制器
  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      this.listeners.push(listener);
    }
  }

  // 注销改变数据的控制器
  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      this.listeners.splice(pos, 1);
    }
  }

  // 增加数据
  public addDataItem(data: Array<CardModel>): void {
    if (data.length > 0) {
      for (let index = 0; index < data.length; index++) {
        this.dataArray.push(data[index]);
      }
      this.notifyDataAdd(0);
    }
  }

  // 删除第一个元素
  public delete1stItem(): void {
    this.dataArray.splice(0, 1);
    this.notifyDataDelete(0);
  }

  // 删除第二个元素
  public delete2ndItem(): void {
    this.dataArray.splice(1, 1);
    this.notifyDataDelete(1);
  }

  // 删除最后一个元素
  public deleteLastItem(): void {
    this.dataArray.splice(-1, 1);
    this.notifyDataDelete(this.dataArray.length);
  }

  // 在指定索引位置删除一个元素
  public deleteItem(index: number): void {
    this.dataArray.splice(index, 1);
    this.notifyDataDelete(index);
  }

  // 重新加载数据
  public reload(): void {
    this.dataArray.splice(1, 1);
    this.dataArray.splice(3, 2);
    this.notifyDataReload();
  }
}

CardModel代码如下:

js 复制代码
/**
 * 小卡片模型
 */
export class CardModel {
  img: ResourceStr; //封面
  title: string; //标题
  userImg: ResourceStr; //用户头像
  userName: string; //用户昵称
  likeCount: string; //点赞量
  constructor(img: ResourceStr, title: string, userImg: ResourceStr, userName: string, likeCount: string) {
    this.img = img;
    this.title = title;
    this.userImg = userImg;
    this.userName = userName;
    this.likeCount = likeCount;
  }
}

最后

  • 希望本文对你有所帮助!
  • 本人如有任何错误或不当之处,请留言指出,谢谢!
相关推荐
世人万千丶6 小时前
Day 5: Flutter 框架 SQLite 数据库进阶 - 在跨端应用中构建结构化数据中心
数据库·学习·flutter·sqlite·harmonyos·鸿蒙·鸿蒙系统
小学生波波6 小时前
HarmonyOS6 - Slider滑动条组件案例
arkts·鸿蒙·slider·鸿蒙开发·harmonyos6·滑动组件
酷酷的鱼17 小时前
跨平台技术选型方案(2026年App实战版)
react native·架构·鸿蒙系统
小学生波波1 天前
HarmonyOS6 - 鸿蒙日历实战案例
arkts·鸿蒙系统·日历·deveco studio·鸿蒙开发·harmonyos6·签到日历
小学生波波1 天前
HarmonyOS6 - 鸿蒙弹窗选择省市区实战案例
arkts·鸿蒙·arkui·鸿蒙开发·harmonyos6·省市区·级联选择
小学生波波1 天前
HarmonyOS6 - 鸿蒙相机拍照和相册选图实战案例
鸿蒙系统·拍照·鸿蒙开发·harmonyos6·图库选择
小学生波波1 天前
HarmonyOS6 - 聊天页面实战案例
arkts·鸿蒙·鸿蒙开发·聊天·harmonyos6
小雨下雨的雨2 天前
鸿蒙PC应用:工程结构解析与配置文件详解
ui·华为·harmonyos·鸿蒙系统
云栖梦泽2 天前
鸿蒙应用的未来发展趋势与前沿技术探索
鸿蒙系统