HarmonyOS 鸿蒙Next中如何实现上拉加载更多
HarmonyOS 鸿蒙Next中如何实现上拉加载更多
如何实现上拉加载更多
【背景知识】
-
PullToRefresh是一款OpenHarmony环境下可用的下拉刷新、上拉加载组件。支持设置内置动画的各种属性,支持设置自定义动画,支持lazyForEarch的数据作为数据源。
PullToRefresh使用限制:
1、目前只支持List、Scroll、Tabs、Grid和WaterFlow系统容器组件;
2、暂不支持设置系统容器组件的弹簧效果和阴影效果,使用时需要将系统组件edgeEffect属性的值设置为(EdgeEffect.None);
3、暂不支持页面触底时自动触发上拉加载功能;
4、暂不支持在页面数据不满一屏时触发上拉加载功能;
5、暂不支持通过代码的方式去触发下拉刷新功能;
6、暂不支持在下拉刷新动画结束时提供手势结束的回调。 -
Refresh:可以进行页面下拉操作并显示刷新动效的容器组件。
-
List组件:列表包含一系列相同宽度的列表项。
-
Button组件:按钮组件通常用于响应用户的点击操作,其类型包括胶囊按钮、圆形按钮、普通按钮、圆角矩形按钮。Button做为容器使用时可以通过添加子组件实现包含文字、图片等元素的按钮。
-
$$运算符:$$运算符为系统组件提供TS变量的引用,使得TS变量和系统组件的内部状态保持同步。
【解决方案】
场景一解决方案:
在项目根目录下的oh-package.json5文件中配置PullToRefresh:
{
// ...
"devDependencies": {
"[@ohos](/user/ohos)/pulltorefresh": "2.1.2"
}
}
在模块目录下的oh-package.json5文件中配置PullToRefresh:
{
"name": "entry",
// ...
"dependencies": {
"[@ohos](/user/ohos)/pulltorefresh": "^2.1.2"
}
}
示例代码实现:
import { PullToRefresh } from '[@ohos](/user/ohos)/pulltorefresh'
@Entry
@Component
struct ScrollCeilingTab {
scroller: Scroller = new Scroller()
private tabscroller: Scroller = new Scroller();
@State itemData: Array<number> = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
tabTitles: Array<string> = ['Tab1', 'Tab2', 'Tab3']
@Builder
private getListView() {
List({ space: 20, scroller: this.tabscroller }) {
ForEach(this.itemData, (item: number) => {
ListItem() {
Text(`${item}`)
.height(80)
.width('100%')
.textAlign(TextAlign.Center)
.backgroundColor(0xDDDDDD)
.margin({ bottom: 5 })
}
})
}
.nestedScroll({
scrollForward: NestedScrollMode.PARENT_FIRST,
scrollBackward: NestedScrollMode.SELF_FIRST
})
.backgroundColor('#eeeeee')
.divider({ strokeWidth: 1, color: 0x222222 })
.edgeEffect(EdgeEffect.None) // 必须设置列表为滑动到边缘无效果
}
@Builder
tabContentData(tabTitle: string) {
TabContent() {
Column() {
PullToRefresh({
data: this.itemData,
scroller: this.tabscroller,
customList: () => {
this.getListView();
},
// 可选项,下拉刷新回调
onRefresh: () => {
return new Promise<string>((resolve, reject) => {
// 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
setTimeout(() => {
resolve('刷新成功');
let num = this.itemData.length
this.itemData.push(num);
}, 500);
});
},
// 可选项,上拉加载更多回调
onLoadMore: () => {
return new Promise<string>((resolve, reject) => {
setTimeout(() => {
resolve('');
let num = this.itemData.length
this.itemData.push(num);
}, 2000);
});
},
customLoad: null,
customRefresh: null,
})
}
}
.tabBar(tabTitle)
.padding({ top: 5, bottom: 5 })
.borderWidth(1)
.borderColor(Color.Red)
}
build() {
Column({ space: 10 }) {
Scroll(this.scroller) {
Column() {
Image($r('app.media.startIcon')).height(70)
Tabs() {
ForEach(this.tabTitles, (title: string) => {
this.tabContentData(title)
})
}.borderWidth(2)
}.width('90%').alignItems(HorizontalAlign.Center)
}.width('100%').align(Alignment.Center).scrollBar(BarState.Off)
}
}
}
- 场景二解决方案:
可以使用$$双向绑定Refresh组件参数refreshing,点击按钮手动控制组件刷新状态实现,示例代码如下:
@Entry
@Component
struct RefreshExample {
@State isRefreshing: boolean = false
@State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
build() {
Column() {
Row() {
Button('开始刷新')
.onClick(() => {
// 手动开始刷新
this.isRefreshing = true
})
Button('结束刷新')
.onClick(() => {
// 手动停止刷新
this.isRefreshing = false
})
}
Refresh({ refreshing: $$this.isRefreshing }) {
List() {
ForEach(this.arr, (item: string) => {
ListItem() {
Text('' + item)
.width('70%')
.height(80)
.fontSize(16)
.margin(2)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
}
}, (item: string) => item)
}
}
.onRefreshing(() => {
// 2秒后自动结束刷新
setTimeout(() => {
this.isRefreshing = false
}, 2000)
})
.backgroundColor(0x89CFF0)
}
}
}
- 场景三解决方案:
可以在外层List使用Refresh组件实现上拉刷新,内层List使用pulltofresh进行下拉加载,代码示例如下:
import { PullToRefresh, PullToRefreshConfigurator } from '[@ohos](/user/ohos)/pulltorefresh'
const tabsList = ["能源", "化工", "塑料", "化纤", "聚氨酯"]
@Component
struct Index {
private refreshScroller: Scroller = new Scroller();
private refreshConfigurator: PullToRefreshConfigurator = new PullToRefreshConfigurator();
@State list: Array<string> =
["a", "b", "c", "d", "e", "f", "a1", "b1", "c1", "d1", "e1", "f1"]
aboutToAppear(): void {
this.refreshConfigurator.setHasRefresh(false);
}
@Builder
getListView() {
List({ space: 10, scroller: this.refreshScroller }) {
ForEach(this.list,
(item: string, idx: number) => {
ListItem() {
Text(item)
.width("100%")
.height(200)
.width('100%')
.backgroundColor("#ffe0dbdb")
}
})
}
.height('100%')
.width("100%")
.scrollBar(BarState.Off)
.edgeEffect(EdgeEffect.None)
.nestedScroll({
scrollForward: NestedScrollMode.PARENT_FIRST,
scrollBackward: NestedScrollMode.SELF_FIRST
})
}
build() {
Column({ space: 10 }) {
PullToRefresh({
// 必传项,列表组件所绑定的数据
data: $list,
refreshConfigurator: this.refreshConfigurator,
// 必传项,需绑定传入主体布局内的列表或宫格组件
scroller: this.refreshScroller,
// 必传项,自定义主体布局,内部有列表或宫格组件
customList: () => {
// 一个用@Builder修饰过的UI方法
this.getListView();
},
// 可选项,上拉加载更多回调
onLoadMore: () => {
return new Promise<string>((resolve, reject) => {
// 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
setTimeout(() => {
resolve('加载更多啦啦啦');
this.list.push('a2');
this.list.push('b2');
}, 2000);
});
},
customLoad: null,
customRefresh: null,
}).width('100%').height('100%')
}.width('100%')
}
}
@Entry
@Component
struct KeyboadPage {
private refreshScroller: Scroller = new Scroller();
@State isRefresh: boolean = false;
build() {
Column({ space: 10 }) {
Refresh({ refreshing: $$this.isRefresh, builder: this.buildRefreshCom() }) {
this.getListView()
}.onRefreshing(() => {
setTimeout(() => {
this.isRefresh = false;
}, 1000)
})
}
.width('100%')
.height('100%')
}
@Builder
buildRefreshCom() {
Row() {
LoadingProgress().height(32)
Text("正在刷新...").fontSize(16).margin({
left: 20,
})
}
.alignItems(VerticalAlign.Center)
}
@Builder
getListView() {
List({ scroller: this.refreshScroller }) {
ListItem() {
Text("第一条")
.width("100%")
.height(300)
.backgroundColor("#ffe0dbdb")
}
ListItem() {
Text("第二条")
.width("100%")
.height(500)
.backgroundColor("#ff74a6ec")
}
ListItem() {
Text("第三条")
.width("100%")
.height(200)
.backgroundColor("#ffdbdfe0")
}
ListItem() {
Tabs({
barPosition: BarPosition.Start,
}) {
ForEach(tabsList,
(item: string, idx: number) => {
TabContent() {
Index()
}
.tabBar(this.watchingTabBuilder(idx, item))
})
}
.width("100%")
.barHeight(50)
.barMode(BarMode.Scrollable)
.onChange((index: number) => {
})
}
}
.edgeEffect(EdgeEffect.None)
.height('100%')
.width('100%')
.scrollBar(BarState.Off)
}
@Builder
watchingTabBuilder(index: number, item: string) {
Text(item)
.fontSize(16)
.fontColor("#121212")
.padding({
left: 15,
right: 15,
top: 12,
bottom: 12
})
.borderRadius(5)
}
}
更多关于HarmonyOS 鸿蒙Next中如何实现上拉加载更多的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
滚动容器的onScrollEdge可以触发触底回调
.onScrollEdge((side: Edge) => {
console.info('To the edge');
})
在HarmonyOS Next中实现上拉加载更多,可通过List组件的onReachEnd事件监听滚动到底部。当触发该事件时,执行加载数据的逻辑。示例代码:
List() {
// 列表内容
}
.onReachEnd(() => {
// 加载更多数据
})
需结合数据源状态管理,避免重复加载。
在HarmonyOS Next中,可以通过以下方式实现上拉加载更多功能:
- 使用ListContainer组件:结合
OnScrollListener
监听滚动事件,当滚动到底部时触发数据加载 - 自定义Refresh组件:通过
Component.ScrolledListener
监听滑动距离,判断是否达到加载阈值 - 使用ArkUI声明式开发:
@State listData: string[] = [...]
@State isLoading: boolean = false
List() {
ForEach(this.listData, (item: string) => {
ListItem() {
Text(item)
}
})
// 加载更多指示器
if (this.isLoading) {
ListItem() {
Progress()
}
}
}
.onReachEnd(() => {
if (!this.isLoading) {
this.loadMoreData()
}
})
关键实现要点:
- 设置合理的加载阈值(如距离底部50px)
- 添加加载状态防止重复请求
- 配合分页参数实现数据增量加载
- 考虑网络异常等边界情况处理
建议结合@ohos.net.http
模块实现数据请求,使用@State
管理加载状态,确保流畅的用户体验。