鸿蒙Harmony实战开发:WaterFlow页面滑动加载最佳实践

148 篇文章 0 订阅
148 篇文章 0 订阅

场景描述

场景一:瀑布流页面多列混排的布局场景,例如: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,//该分组的列间距,不设置时使用瀑布流的columnsGap

rowsGap: 10,//该分组的行间距,不设置时使用瀑布流的rowsGap

margin: { 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 = 0

let oneOrTwo = 0

while (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 }

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。 

为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:

 →【纯血版鸿蒙全套最新学习文档】希望这一份鸿蒙学习文档能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.学习视频+学习PDF文档

HarmonyOS Next 最新全套视频教程 (鸿蒙语法ArkTS、TypeScript、ArkUI教程……)

​​

 纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

                   

​​​​鸿蒙APP开发必备

​​

总结

【纯血版鸿蒙全套最新学习文档】

总的来说,华为鸿蒙不再兼容安卓,对程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,才能在这个变革的时代中立于不败之地。 

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值