概述
Refresh组件支持下拉刷新,包裹list组件,下拉事件中更新列表
这里我们需要提前了解一下@Builder装饰器 的基本用法
ArkUI提供了一种轻量的UI元素复用机制@Builder,该自定义组件内部UI结构固定,仅与使用方进行数据传递,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。
为了简化语言,我们将@Builder装饰的函数也称为"自定义构建函数"。
具体用法可参考官网文档:文档中心
在后面我们也会去详细的讲解 @Builder装饰器 的使用
对于滚动有List和Scroll,List适合数量不确定的滚动,比如评论列表等;Scroll适合数量确定的滚动
上拉刷新
这里主要用到 Refresh组件 的 onRefreshing 函数
@Entry
@Component
struct Index {
// 是否需要刷新
@State
refreshing: boolean = false
// 自定义构建函数--给组件传递
@Builder
refreshContent() {
// Text('正在玩命加载中...')
// .width('100%')
// .textAlign(TextAlign.Center)
// .backgroundColor(Color.Pink)
Row({space: 8}) {
LoadingProgress()
.height(24)
Text('正在玩命加载中...')
}
.width('100%')
.padding(12)
.justifyContent(FlexAlign.Center)
}
// 定义随机数据
@State
list: number[] = Array(20).fill(Date.now())
// 下拉加载用到
scroller:Scroller = new Scroller()
@State
isEnd: boolean = false
build() {
RelativeContainer() {
// Refresh 刷新组件
// 参数说明:refreshing 组件当前是否处于刷新中状态;builder 自定义刷新区域显示内容(结构体),参数可选
Refresh({refreshing: $$this.refreshing, builder: this.refreshContent}) {
List() {
ForEach(this.list, (item: number) => {
ListItem() {
Row() {
Text(item.toString())
.width('100%')
.padding(20)
.border({
width: {
bottom: 1
},
style: {
bottom: BorderStyle.Dashed
},
color: Color.Gray
})
}
}
})
}
}
// 监听是否刷新完毕(真正的刷新操作)-从而进行数据更新操作
.onRefreshing(() => {
setTimeout(() => {
// 更新数据
this.list = Array(20).fill(Date.now())
// 手动关闭刷新状态
this.refreshing = false
}, 1000)
})
}
.width('100%')
.height('100%')
}
}
下拉加载
注册三个事件,开始滚动,滚动结束,滚动至列表尾部(触发两次,滚动至+回弹)
设置变量是否滚动底部,开始滚动false,滚动至列表尾部true,滚动结束判断变量进行数据追加
触底了--只有触底了才会进行数据加载,这里会出现加载两次的情况,因此在这里不适合进行数据的请求操作
对于数据的请求我们需要利用 onScrollStart 和 onScrollStop 和 onReachEnd 三个进行联合判断,从而进行数据请求操作
数据请求逻辑:1.开始滚动,更新状态为没有触底不进行数据加载;2.停止滚动,是否触底了触底了才加载数据,反之不加载数据;3.触底,记录触底了
下拉加载数据完成了应该让滚动条滚动到底部去,不然不知道是否已经加载成功了
import { promptAction } from '@kit.ArkUI'
import HmLoading from './components/HmLoading'
@Entry
@Component
struct Index {
// 是否需要刷新
@State
refreshing: boolean = false
// 自定义构建函数--给组件传递
@Builder
refreshContent() {
// Text('正在玩命加载中...')
// .width('100%')
// .textAlign(TextAlign.Center)
// .backgroundColor(Color.Pink)
Row({space: 8}) {
LoadingProgress()
.height(24)
Text('正在玩命加载中...')
}
.width('100%')
.padding(12)
.justifyContent(FlexAlign.Center)
}
// 定义随机数据
@State
list: number[] = Array(20).fill(Date.now())
// 下拉加载用到:用于下拉加载成功后让滚动条滚动到底部自动
scroller:Scroller = new Scroller()
@State
isEnd: boolean = false
@State
isLoading: boolean = false
total:number = 43
build() {
Stack() {
RelativeContainer() {
// Refresh 刷新组件
// 参数说明:refreshing 组件当前是否处于刷新中状态;builder 自定义刷新区域显示内容(结构体),参数可选
Refresh({refreshing: $$this.refreshing, builder: this.refreshContent}) {
List({scroller: this.scroller}) {
ForEach(this.list, (item: number) => {
ListItem() {
Row() {
Text(item.toString())
.width('100%')
.padding(20)
.border({
width: {
bottom: 1
},
style: {
bottom: BorderStyle.Dashed
},
color: Color.Gray
})
}
}
})
if(this.list.length > this.total) {
ListItem() {
Row() {
Text('我是有底线的~')
}
.width('100%')
.padding(12)
.justifyContent(FlexAlign.Center)
}
}
}
// 开始滚动
.onScrollStart(() => {
promptAction.showToast({
message: '开始滚动'
})
this.isEnd = false;
})
// 停止滚动
.onScrollStop(() => {
// 节流效果
if(this.isLoading || this.list.length > this.total) return;
promptAction.showToast({
message: '停止滚动'
})
if(this.isEnd) {
this.isLoading = true;
// 数据加载
setTimeout(() => {
const list:number[] = Array(10).fill(Math.random())
this.list.push(...list)
this.scroller.scrollEdge(Edge.Bottom)
this.isLoading = false;
}, 1000)
}
})
// 触底了--只有触底了才会进行数据加载,这里会出现加载两次的情况,因此在这里不适合进行数据的请求操作
// 对于数据的请求我们需要利用 onScrollStart 和 onScrollStop 和 onReachEnd 三个进行联合判断,从而进行数据请求操作
// 数据请求逻辑:1.开始滚动,更新状态为没有触底不进行数据加载;2.停止滚动,是否触底了触底了才加载数据,反之不加载数据;3.触底,记录触底了
.onReachEnd(() => {
promptAction.showToast({
message: '触底了'
})
this.isEnd = true;
})
}
// 监听是否刷新完毕(真正的刷新操作)-从而进行数据更新操作
.onRefreshing(() => {
setTimeout(() => {
// 更新数据
this.list = Array(20).fill(Date.now())
// 手动关闭刷新状态
this.refreshing = false
}, 1000)
})
}
.width('100%')
.height('100%')
if(this.isLoading) {
Column() {
HmLoading()
}
.height('100%')
.width('100%')
.backgroundColor('#ba0a0000')
.justifyContent(FlexAlign.Center)
}
}
}
}