鸿蒙5.0实战案例:基于WaterFlow的页面滑动加载

devtools/2025/2/27 5:13:46/

往期推文全新看点(文中附带全新鸿蒙5.0全栈学习笔录)

✏️ 鸿蒙(HarmonyOS)北向开发知识点记录~

✏️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~

✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?

✏️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~

✏️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?

✏️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?

✏️ 记录一场鸿蒙开发岗位面试经历~

✏️ 持续更新中……


场景描述

  • 场景一:瀑布流页面多列混排的布局场景,例如:10个item在2列内布局,中间5个item在1列内撑满宽度布局,后10个item在3列内布局。
  • 场景二:瀑布流页面中某一个Item可以固定展示在某一个位置,从而实现吸顶效果

方案描述

场景一:

waterFlow支持自定义Item,从而在WaterFlow内完成多列混排的自定义布局,同时懒加载保证性能。

方案

通过sections配置分组信息,并初始化瀑布流分组,通过splice替换/添加新分组。

核心代码

1、计算FlowItem宽/高,设置FlowItem的宽/高数组,通过对应Item,设置FlowItem的宽/高。

2、通过sections配置分组信息,并初始化瀑布流分组,具体根据 SectionOptions需要自定义。可通过Item和分组分组信息中itemsCount设置指定Item的布局,例如Item=5,第一个分组中itemsCount: 4,Item=5为第二个分组的第二个Item(此处Item从0开始)。

3、即将触底时提前增加数据,添加加新分组到瀑布流末尾。

//计算FlowItem宽/高getSize() {let ret = Math.floor(Math.random() * this.maxSize)return (ret > this.minSize ? ret : this.minSize)}// 设置FlowItem的宽/高数组setItemSizeArray() {for (let i = 0; i < 100; i++) {this.itemWidthArray.push(this.getSize())this.itemHeightArray.push(this.getSize())}}//配置分组信息,可通过Item和分组信息中itemsCount设置指定Item的布局,例如Item=5,第一个分组中为itemsCount: 4,Item=5为第二个分组的第二个Item(此处Item从0开始)@State sections: WaterFlowSections = new WaterFlowSections()oneColumnSection: SectionOptions = {itemsCount: 4,//分组中FlowItem数量,必须是正整数。crossCount: 1,//纵向布局时为列数,横向布局时为行数columnsGap: 5,//该分组的列间距,不设置时使用瀑布流的columnsGaprowsGap: 10,//该分组的行间距,不设置时使用瀑布流的rowsGapmargin: { top: 10, left: 5, bottom: 10, right: 5 },onGetItemMainSizeByIndex: (index: number) => {//瀑布流组件布局过程中获取指定index的FlowItem的主轴大小return 150}}twoColumnSection: SectionOptions = {itemsCount: 20,crossCount: 2,onGetItemMainSizeByIndex: (index: number) => {return this.itemHeightArray[index 100]}}//初始化分组信息aboutToAppear() {this.setItemSizeArray()let sectionOptions: SectionOptions[] = []let count = 0let oneOrTwo = 0while (count < this.dataCount) {//当oneOrTwo为偶数时加载第一个分组,为奇数时加载第二个分组if (oneOrTwo++ % 2 == 0) {sectionOptions.push(this.oneColumnSection)count += this.oneColumnSection.itemsCount} else {sectionOptions.push(this.twoColumnSection)count += this.twoColumnSection.itemsCount}}//splice(start: number, deleteCount?: number, sections?: Array<SectionOptions>)//start为正数时,表示从瀑布流首位开始计算,到start位置时,splicet替换现有分组//start为负数时,表示从瀑布流末尾开始,splicet添加新分组//deleteCount 表示要从start开始删除的分组数量this.sections.splice(-1, 0, sectionOptions)}//即将触底时提前增加数据waterFlow({ scroller: this.scroller, sections: this.sections }) {LazyForEach(this.dataSource, (item: number) => {...}.onScrollIndex((first: number, last: number) => {// 即将触底时提前增加数据//剩最后二十条数据时,提前增加数据,设置新的分组信息,将新分组添加到瀑布流末尾if (last + 20 >= this.dataSource.totalCount()) {for (let i = 0; i < 100; i++) {this.dataSource.addLastItem()}let newSection: SectionOptions = {itemsCount: 100,crossCount: 2,onGetItemMainSizeByIndex: (index: number) => {return this.itemHeightArray[index % 100]}}this.sections.push(newSection)}})

场景二:

页面中某个Item跟随页面滑动,到达吸顶位置时,继续滑动,吸顶元素保持不动,其他元素继续滑动。

方案

在瀑布流分组中为要吸顶的部分预留出位置,监听瀑布流滚动事件,吸顶部分基于瀑布流滚动后的偏移量设置位置,让吸顶部分跟随瀑布流一起滚动,吸顶部分到顶后固定不动。

核心代码

1、在第一个分组中剔除Item=1,为吸顶部分留出位置,避免吸顶部分遮挡其余Item。

2、在数据渲染时也要剔除Item=1,其余Item正常渲染。

3、设置瀑布流的onWillScroll事件回调,监听瀑布流的滚动,吸顶部分基于瀑布流滚动后的偏移量设置位置,让吸顶部分跟随瀑布流一起滚动。吸顶部分初始位置为预留的Item=1的位置,吸顶部分到达顶部以后固定在顶部位置。

//预留吸顶部分位置oneColumnSection: SectionOptions = {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}}}.....WaterFlow({ scroller: this.scroller, sections: this.sections }) {LazyForEach(this.dataSource, (item: number) => {FlowItem() {Column(){//剔除Item=1,为吸顶部分留出位置//可基于Item和分组数量设置指定Item的布局,例如Item=3为第二个分组的第一个Item(此处Item从0开始)if (item!=1) {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)}.....//onWillScroll瀑布流滑动前触发,返回当前帧将要滑动的偏移量和当前滑动状态。返回的偏移量为计算得到的将要滑动的偏移量值,并非最终实际滑动偏移。//监听滚动事件,获取当前滚动偏移量和将要滚动的偏移量,scrollOffset保存滚动后的偏移量。.onWillScroll((offset:number) => {this.scrollOffset = this.scroller.currentOffset().yOffset + offset //currentOffset 当前滚动的偏移量//未滚动时this.scrollOffset初始值为0})Stack() {........}.backgroundColor(Color.White)}.alignItems(HorizontalAlign.Start)}.height(100).hitTestBehavior(HitTestMode.Transparent)//this.scrollOffset滚动后的偏移量 滚动后的偏移量大于吸顶部分到顶部距离时,固定在顶部不动//这里220为第一个Item高度200和第一个Item顶部和底部10的间隔.position( {x: 0, y: this.scrollOffset >= 220 ? 0 : 220- this.scrollOffset })

http://www.ppmy.cn/devtools/162974.html

相关文章

深度集成DeepSeek大模型:WebSocket流式聊天实现

目录 5分钟快速接入DeepSeek大模型&#xff1a;WebSocket实时聊天指南创建应用开发后端代码 (Python/Node.js)结语 5分钟快速接入DeepSeek大模型&#xff1a;WebSocket实时聊天指南 创建应用 访问DeepSeek官网 前往 DeepSeek官网。如果还没有账号&#xff0c;需要先注册一个。…

体育数据网站推荐系统开发:赛事数据、前瞻分析与智能推荐

体育数据网站作为集赛事数据、前瞻分析、专家解读于一体的综合平台&#xff0c;其推荐系统的开发需要充分考虑多维度数据的整合与应用。本文将深入探讨如何构建一个智能化的体育数据推荐系统。 一、系统架构设计 数据采集层&#xff1a; 实时赛事数据API接入 专家分析内容抓…

游戏引擎学习第120天

仓库:https://gitee.com/mrxiao_com/2d_game_3 上次回顾&#xff1a;周期计数代码 我们正在进行一个项目的代码优化工作&#xff0c;目标是提高性能。当前正在优化某个特定的代码片段&#xff0c;已经将其执行周期减少到48个周期。为了实现这一目标&#xff0c;我们设计了一个…

flutter Running Gradle task ‘assembleDebug‘...

这个和单独的android还不太一样 Flutter 在Android studio运行时卡在Running Gradle task assembleDebug... - 简书

基于 JavaWeb 的 SSM+Maven 微信小程序快递柜管理系统设计和实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

什么是HTTP/2协议?NGINX如何支持HTTP/2并提升网站性能?

HTTP/2是一种用于在Web浏览器和服务器之间进行通信的协议&#xff0c;旨在提高网站性能和加载速度。它是HTTP/1.1的继任者&#xff0c;引入了许多优化和改进&#xff0c;以适应现代Web应用的需求。HTTP/2的主要目标是减少延迟、提高效率&#xff0c;以及更好地支持并发请求。 …

deepseek自动化代码生成

使用流程 效果第一步&#xff1a;注册生成各种大模型的API第二步&#xff1a;注册成功后生成API第三步&#xff1a;下载vscode在vscode中下载agent&#xff0c;这里推荐使用cline 第四步&#xff1a;安装完成后&#xff0c;设置模型信息第一步选择API provider&#xff1a; Ope…

Vue3 + Vite + TS,使用 配置项目别名属性:server

官网地址传送门 点哇点哇&#xff0c;vite 官网传送门 直接上马 server: {https: false, // 是否开启 httpsopen: true, // 是否自动在浏览器中打开port: 8001, // 端口号host: "0.0.0.0",// 跨域代理proxy: {/api: {target: "http://localhost:3000", …