首页 > 其他分享 >HarmonyOS开发之WaterFlow组件

HarmonyOS开发之WaterFlow组件

时间:2024-09-27 13:50:20浏览次数:10  
标签:item number WaterFlow HarmonyOS State let 组件 100 sections

在HarmonyOS应用开发中,瀑布流布局因其灵活性和美观性而广受欢迎。HarmonyOS NEXT 提供了强大的 WaterFlow 组件,可以帮助开发者轻松实现瀑布流布局,并支持多种自定义布局和性能优化特性。本文将通过两个具体场景,详细介绍如何使用 WaterFlow 组件实现页面滑动加载和吸顶效果。

场景一:瀑布流页面多列混排的布局场景

场景描述

在一个瀑布流页面中,不同区域的布局可能有所不同,例如前10个item在2列内布局,中间5个item在1列内撑满宽度布局,后10个item在3列内布局。

实现思路

  1. 计算FlowItem宽/高:动态计算每个item的宽高,确保布局的多样性。
  2. 设置FlowItem的宽/高数组:预设每个item的宽高,以便在布局时使用。
  3. 配置分组信息:通过 sections 配置分组信息,支持不同列数的布局。
  4. 懒加载:在即将触底时提前加载更多数据,确保性能。

核心代码

@Entry
@Component
struct WaterFlowLayout {
  @State dataSource: Array<number> = [];
  @State sections: WaterFlowSections = new WaterFlowSections();
  @State itemWidthArray: Array<number> = [];
  @State itemHeightArray: Array<number> = [];
  @State dataCount: number = 100;
  @State maxSize: number = 200;
  @State minSize: number = 100;
  @State scroller: Scroller = new Scroller();

  getSize() {
    let ret = Math.floor(Math.random() * this.maxSize);
    return (ret > this.minSize ? ret : this.minSize);
  }

  setItemSizeArray() {
    for (let i = 0; i < 100; i++) {
      this.itemWidthArray.push(this.getSize());
      this.itemHeightArray.push(this.getSize());
    }
  }

  aboutToAppear() {
    this.setItemSizeArray();
    let sectionOptions: SectionOptions[] = [];
    let count = 0;
    let oneOrTwo = 0;
    while (count < this.dataCount) {
      if (oneOrTwo++ % 2 == 0) {
        sectionOptions.push({
          itemsCount: 4,
          crossCount: 1,
          columnsGap: 5,
          rowsGap: 10,
          margin: { top: 10, left: 5, bottom: 10, right: 5 },
          onGetItemMainSizeByIndex: (index: number) => 150
        });
        count += 4;
      } else {
        sectionOptions.push({
          itemsCount: 20,
          crossCount: 2,
          onGetItemMainSizeByIndex: (index: number) => this.itemHeightArray[index % 100]
        });
        count += 20;
      }
    }
    this.sections.splice(-1, 0, sectionOptions);
  }

  build() {
    Column() {
      WaterFlow({ scroller: this.scroller, sections: this.sections })
        .height('100%')
        .width('100%')
        .onScrollIndex((first: number, last: number) => {
          if (last + 20 >= this.dataSource.length) {
            for (let i = 0; i < 100; i++) {
              this.dataSource.push(this.dataSource.length);
            }
            let newSection: SectionOptions = {
              itemsCount: 100,
              crossCount: 2,
              onGetItemMainSizeByIndex: (index: number) => this.itemHeightArray[index % 100]
            };
            this.sections.push(newSection);
          }
        })
        .children(LazyForEach(this.dataSource, (item: number) => {
          FlowItem() {
            Column() {
              Image(`./Image/${item % 10}.png`)
                .objectFit(ImageFit.Cover)
                .width('90%')
                .height(100)
                .layoutWeight(1)
                .margin(5);
              Text("必吃榜").fontSize(12).height('16');
            }
          }
          .width('100%')
          .height(this.itemHeightArray[item % 100])
          .backgroundColor(Color.White);
        }, (item: string) => item));
    }
  }
}

场景二:瀑布流页面中某一个Item固定展示在某一个位置

场景描述

在瀑布流页面中,某个Item需要固定展示在某个位置,当页面滑动时,该Item在到达吸顶位置后保持不动,其他内容继续滑动。

实现思路

  1. 预留吸顶部分位置:在第一个分组中剔除特定的Item,为吸顶部分留出位置。
  2. 数据渲染:在数据渲染时剔除特定的Item,确保吸顶部分不被覆盖。
  3. 监听滚动事件:通过 onWillScroll 回调监听滚动事件,根据滚动偏移量调整吸顶部分的位置。

核心代码

@Entry
@Component
struct StickyItemLayout {
  @State dataSource: Array<number> = [];
  @State sections: WaterFlowSections = new WaterFlowSections();
  @State itemWidthArray: Array<number> = [];
  @State itemHeightArray: Array<number> = [];
  @State dataCount: number = 100;
  @State maxSize: number = 200;
  @State minSize: number = 100;
  @State scroller: Scroller = new Scroller();
  @State scrollOffset: number = 0;

  getSize() {
    let ret = Math.floor(Math.random() * this.maxSize);
    return (ret > this.minSize ? ret : this.minSize);
  }

  setItemSizeArray() {
    for (let i = 0; i < 100; i++) {
      this.itemWidthArray.push(this.getSize());
      this.itemHeightArray.push(this.getSize());
    }
  }

  aboutToAppear() {
    this.setItemSizeArray();
    let sectionOptions: SectionOptions[] = [];
    sectionOptions.push({
      itemsCount: 3,
      crossCount: 1,
      columnsGap: 5,
      rowsGap: 10,
      margin: { top: 10, left: 5, bottom: 10, right: 5 },
      onGetItemMainSizeByIndex: (index: number) => {
        if (index == 1) {
          return 100; // 剔除Item=1,为吸顶部分留出位置
        } else {
          return 200;
        }
      }
    });
    this.sections.splice(-1, 0, sectionOptions);
  }

  build() {
    Column() {
      WaterFlow({ scroller: this.scroller, sections: this.sections })
        .height('100%')
        .width('100%')
        .onScrollIndex((first: number, last: number) => {
          if (last + 20 >= this.dataSource.length) {
            for (let i = 0; i < 100; i++) {
              this.dataSource.push(this.dataSource.length);
            }
            let newSection: SectionOptions = {
              itemsCount: 100,
              crossCount: 2,
              onGetItemMainSizeByIndex: (index: number) => this.itemHeightArray[index % 100]
            };
            this.sections.push(newSection);
          }
        })
        .onWillScroll((offset: number) => {
          this.scrollOffset = this.scroller.currentOffset().yOffset + offset;
        })
        .children(LazyForEach(this.dataSource, (item: number) => {
          if (item != 1) {
            FlowItem() {
              Column() {
                Image(`./Image/${item % 10}.png`)
                  .objectFit(ImageFit.Cover)
                  .width('90%')
                  .height(100)
                  .layoutWeight(1)
                  .margin(5);
                Text("必吃榜").fontSize(12).height('16');
              }
            }
            .width('100%')
            .height(this.itemHeightArray[item % 100])
            .backgroundColor(Color.White);
          }
        }, (item: string) => item));

      Stack() {
        Column() {
          // 吸顶部分
          Text("吸顶内容")
            .fontSize(20)
            .fontColor(Color.Black)
            .width('100%')
            .height(100)
            .hitTestBehavior(HitTestMode.Transparent)
            .position({ x: 0, y: this.scrollOffset >= 220 ? 0 : 220 - this.scrollOffset });
        }
      }
      .alignItems(HorizontalAlign.Start)
      .backgroundColor(Color.White);
    }
  }
}

标签:item,number,WaterFlow,HarmonyOS,State,let,组件,100,sections
From: https://blog.51cto.com/u_15171169/12128570

相关文章

  • uniapp [全端兼容] - 详细实现日历“平铺方式“直接在页面上显示出来,而并非嵌套在弹出
    前言如果您需要“纯弹框式”日历,请访问这篇文章。在uni-app全平台兼容(H5网页网站、支付宝/微信小程序、安卓App、苹果App、nvue)开发中,详解实现让日历以平铺、全屏的形式直接放到页面上,而并非常见的弹框及弹出式窗口才能打开日历进行选择,uniApp不套在弹框里的日历插......
  • 鸿蒙(HarmonyOS)--声明式UI、自定义组件
    目录1.基础语法概述2.声明式UI描述2.1创建组件2.1.1无参数2.1.2有参数2.2配置属性2.3配置事件 2.4配置子组件3.自定义组件3.1创建自定义组件3.1.1基本使用3.1.2组件属性、方法3.1.3通用样式事件 3.2页面和自定义组件生命周期3.2.1自定义组件的创建......
  • JEMETE自恢复保险丝可保护USB Type-C连接器免受静电放电和过热影响的组件
    自恢复保险丝保护USBType-C连接器 今天的消费者已经很快地对采用USB-C或USB-TypeC通信接口标准的移动设备变得依赖——从智能手机和平板电脑到可穿戴设备和笔记本电脑。因此,设计针对静电放电 (ESD) 和过热条件的强大保护从未像现在这样重要。 为了处理更高的数据传输速率......
  • vue父子组件的生命周期加载顺序
    vue父子组件的生命周期加载顺序官网里vue组件的生命周期钩子汇总列举如下:生命周期单个vue组件的生命周期执行顺序已经非常熟悉了。但是,如果有嵌套组件,父子组件的生命周期的执行顺序是什么呢?嵌套组件又分为2种情况:一种是在template直接引入(大部分场景),另一种是element......
  • Hadoop三大组件之HDFS(二)
    HDFS常用操作命令Hadoop分布式文件系统(HDFS)提供了灵活且高效的文件管理方式,类似于Linux文件系统。本文将介绍常用的HDFS操作命令,帮助您更好地掌握HDFS的基本操作。1.查看HDFS内容HDFS的目录结构与Linux类似,顶层目录为/。1.1通过浏览器查看可以通过......
  • 类组件中的 React Hook
    介绍在某些情况下,我们假设您必须在基于react类的组件中使用reacthook概念。但是正如你所知,如果你想在基于类的组件中直接使用它们,反应钩子只能在功能组件中工作。它将出现错误。那么如何做呢,有一个解决方案。有3步解决方案创建自定义hook,(你可以直接使用hook,但不会获得更多好......
  • 编写您的第一个 Web 组件(学习 Modulojs - 第 f 部分
    ?欢迎所有新订阅者和返回的组件编码者!我即将开始一个新的10部分教程系列。虽然我的其他教程使用modulo.js构建特定的、有趣的小应用程序,例如口袋妖怪舞会、复古挤压文本编辑器或视频游戏画廊,但本教程系列将建立在基本原则上,从第一部分开始:什么是web组件吗?html和css......
  • 无径之林DirectX组件报错大起底:原因、影响及修复步骤
    一、报错原因无径之林游戏在运行过程中,如果DirectX组件出现报错,通常是由以下几个原因造成的:DirectX版本问题:DirectX版本过低、损坏或未正确安装,都可能导致游戏无法正确调用DirectX的功能,从而引发报错。显卡驱动问题:显卡驱动程序过时、不兼容或安装不正确,会直接影响DirectX......
  • UniApp组件与微信小程序组件对照学习
    UniApp只是一个第三方的开发工具,借鉴各种平台的能力,UniApp的组件也借鉴了微信小程序的组件,我们学习时,可以进行对照学习,我们在用UniApp开发微信小程序时,UniApp也只是将代码转成了微信小程序的代码,还是需要了解微信小程序开发,才能开发出微信小程序的。下面我们来进行对应学习1......
  • pubsub-js库实现跨组件数据传递
    pubsub-js库实现跨组件数据传递基本概念与作用为什么使用pubsub-js?示例一:基本使用示例二:多订阅者示例三:带参数的消息示例四:使用Vuex结合pubsub-js示例五:错误处理与调试实际开发中的使用技巧在Vue.js应用中,组件之间的通信是常见需求之一。Vue提供了多种方式......