鸿蒙的Component不支持泛型。。。
鸿蒙的组件不支持泛型,有两种方案解决
- 拿Object承接,然后使用的时候,强转回来
- 使用联合类型,但是前提得知道所有的类型(放弃)
图
自定义组件 RefreshList
- 下拉刷新我们可以使用
Refresh
, - 上拉更多,有两种方案,推荐使用第二种,可以更快的现实UI,加载时机更快
- 使用
onReachEnd()
监听到滑动到底部 - 使用
onScrollIndex
监听滑动到倒数第二个,或者 第三个的时候,开始加载更多 - 使用 Item 的
onAppear
监听当前index是 倒数第二个,或者 第三个的时候,开始加载更多
- 使用
下拉刷新
自定义RefreshList,由于Component不支持泛型,并且next版本不能写any
,暂时写string[] 数组
先定义一个Component
@Component
@Preview
export struct RefreshList {
}
首先想一下我们的刷新都需要哪些参数
-
加载更多的回调
-
刷新的时候回调
-
是否正在刷新
-
加载更多的枚举
- 初始化
- 加载更多中
- 加载失败
- 加载结束
- 加载完成(没有更多的数据了)
-
listItem ,外界的listItem
-
刷新的文案
- 刷新成功
- 正在刷新。。。
- 继续下拉刷新
- 松手开始刷新
@Component
@Preview
export struct RefreshList {
// 数据源
@Watch('onDataChange')
@Link data: Object[]
@Require scroller: Scroller = new Scroller()
// 加载更多的回调
@Require onLoadMore: () => void = () => {
}
// 刷新的时候回调
@Require onRefresh: () => void = () => {
}
// 是否正在刷新
@Link isRefresh: boolean
// 加载更多的枚举
@Watch('onLoadMoreStateChange')
@Link loadMoreState: LoadMoreState
// list 单个item
@BuilderParam listItem: (item: Object, index: number) => void
// 刷新的文案
@State refreshText: string = '加载中。。。'
@State loadingText: string = '正在加载。。。'
// 刷新文案左边的图片
@State refreshIcon: PixelMap | ResourceStr | DrawableDescriptor = $r("app.media.arrow_down")
}
自定义 Refresh的builder
// 下拉刷新的自定义builder
@Builder
refreshBuild() {
Row({ space: 10 }) {
if (this.isRefresh) {
Progress({ value: 0, total: 100, type: ProgressType.Ring })
.width(40).color(Color.Gray)
.style({ strokeWidth: 5, status: ProgressStatus.LOADING })
} else {
Image(this.refreshIcon).width(50).height(50)
}
// 刷新的文案
Text(this.refreshText)
}.alignItems(VerticalAlign.Center)
}
Reresh的逻辑
Refresh({ refreshing: $$this.isRefresh, builder: this.refreshBuild }) {
List({ scroller: this.scroller }) {
ForEach(this.data, (item: Object, index: number) => {
ListItem() {
this.listItem(item, index)
}
}, (item: Object) => item)
this.loadMore()
}
.onScrollIndex((start: number, end: number, center: number) => {
// 有子组件划入或划出List显示区域时触发。从API version 10开始,List显示区域中间位置子组件变化时也会触发
if (end >= this.data.length - 1) {
// 显示加载
console.log(`end = ${end} length = ${this.data.length} this.loadMoreState=>${this.loadMoreState}`)
// 如果是初始化状态,或者 加载更多的时候,进去刷新
if (this.loadMoreState == LoadMoreState.LoadFinish || this.loadMoreState == LoadMoreState.None) {
this.loadMoreState = LoadMoreState.Loading
this.onLoadMore()
}
}
})
.width('100%')
.height('100%')
}
.onStateChange((refreshStatus: RefreshStatus) => {
switch (refreshStatus) {
case RefreshStatus.Inactive:
// 默认未下拉状态
break
case RefreshStatus.Drag:
//下拉中,下拉距离小于刷新距离。
this.refreshText = '继续下拉加载'
this.refreshIcon = $r("app.media.arrow_down")
break
case RefreshStatus.OverDrag:
// 下拉中,下拉距离超过刷新距离。
this.refreshText = '松手即可加载'
this.refreshIcon = $r("app.media.arrow_up")
break
case RefreshStatus.Refresh:
//下拉结束,回弹至刷新距离,进入刷新状态。
this.refreshText = '加载中。。。'
break
case RefreshStatus.Done:
// 刷新结束,返回初始状态(顶部)。
//下拉结束,回弹至刷新距离,进入刷新状态。
this.refreshText = '成功'
this.refreshIcon = $r("app.media.refresh_success")
break
}
console.info('Refresh onStatueChange state is ' + refreshStatus)
})
.onRefreshing(this.onRefresh)
.refreshOffset(OFFSET)
loadmore组件
@Builder
loadMore() {
ListItem() {
Row() {
// 如果是正在加载更多显示个loading
if (this.loadMoreState == LoadMoreState.Loading) {
LoadingProgress().width(30).height(30)
}
// 加载更多的文案
Text(this.loadingText)
.fontSize(20)
.align(Alignment.Center)
.height(100)
.textAlign(TextAlign.Center)
}
.justifyContent(FlexAlign.Center)
.alignItems(VerticalAlign.Center)
.width('100%')
}
}
使用
import { LoadMoreState, RefreshList } from '../../component/RefreshList';
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct ListDemo {
@State message: string = 'Hello World';
@State data: string[] = []
@State isRefresh: boolean = false
@State isLoadMore: boolean = false
@State loadMoreState: LoadMoreState = LoadMoreState.None
scroller: Scroller = new Scroller()
index: number = 0
aboutToAppear(): void {
for (let index = 0; index < 15; index++) {
// this.data.push(`${Math.floor(Math.random() * 100)}`)
this.data.push(index.toString())
}
console.error('onPageShow')
}
@Builder
listItem(item: Object, index: number) {
Text(item as string)
.fontSize(30)
.align(Alignment.Center)
.height(100)
.width('100%')
.textAlign(TextAlign.Center)
.onClick(() => {
promptAction.showToast({ message: `点击的位置是:${index} , 内容是:${item}` })
})
}
build() {
RelativeContainer() {
RefreshList({
data: this.data,
isRefresh: this.isRefresh,
loadMoreState: this.loadMoreState,
scroller: this.scroller,
onLoadMore: () => {
return new Promise<string>((resolve, reject) => {
// 模拟网络请求操作
setTimeout(() => {
resolve('加载更多成功');
console.log(`执行加载更多`)
let arr2 = [`${this.index++}`, `${this.index++}`, `${this.index++}`, `${this.index++}`, `${this.index++}`]
this.data.push(...arr2)
this.isLoadMore = false
if (this.index > 9) {
this.loadMoreState = LoadMoreState.LoadEnd
} else {
this.loadMoreState = LoadMoreState.LoadFinish
}
}, 2000);
});
},
onRefresh: () => {
return new Promise<string>((resolve, reject) => {
// 模拟网络请求操作
setTimeout(() => {
resolve('刷新成功');
promptAction.showToast({ message: '刷新成功' })
this.data = this.getData();
this.isRefresh = false
}, 2000);
});
},
listItem: this.listItem
}).height('100%').width('100%')
}
.height('100%')
.width('100%')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}
getData(): string[] {
let addData: string[] = []
for (let index = 0; index < 20; index++) {
addData.push(`${Math.floor(Math.random() * 100)}`)
}
return addData;
}
}