效果图:
一:下载安装(地址:OpenHarmony-SIG/PullToRefresh)
ohpm install @ohos/pulltorefresh
二:使用lazyForEarch的数据作为数据源
export class BasicDataSource implements IDataSource{
private listeners: DataChangeListener[] = []
public totalCount(): number {
return 0
}
public getData(index: number): Object {
return index
}
// 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener')
this.listeners.push(listener)
}
}
// 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener')
this.listeners.splice(pos, 1)
}
}
// 通知LazyForEach组件需要重载所有子组件
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded()
})
}
// 通知LazyForEach组件需要在index对应索引处添加子组件
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index)
})
}
// 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index)
})
}
// 通知LazyForEach组件需要在index对应索引处删除该子组件
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index)
})
}
// 数据移动起始位置与数据移动目标位置交换完成后调用
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to)
})
}
}
export class MyDataNewSource extends BasicDataSource{
private dataArray: string[]=[]
public totalCount(): number {
return this.dataArray.length
}
public getData(index: number): Object {
return this.dataArray[index]
}
public addData(index: number, data: string): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(index)
}
public pushData(data: string): void {
this.dataArray.push(data)
this.notifyDataAdd(this.dataArray.length - 1)// 重新加载
}
public clear():void{
this.dataArray=[]
}
}
三:快速使用
import router from '@ohos.router';
import { dateList } from '../model/wallpaperBeanList';
import weatherApi from '../DbUtils/WeatherApi';
import { MyDataNewSource} from '../DbUtils/MyDataSource';
import { PullToRefresh, PullToRefreshConfigurator } from '@ohos/pulltorefresh'
@Component
export struct WallpaperPage {
@State typeID: number = 0
@State wallpaperUrlList: dateList [] = []
dataSource: MyDataNewSource = new MyDataNewSource()
// 需绑定列表或宫格组件
private scroller: Scroller = new Scroller()
timer: null | number = null
private currentPage: number = 1;//当前页码
private pageSize: number = 12; // 默认加载数量
private refreshConfigurator: PullToRefreshConfigurator = new PullToRefreshConfigurator();
aboutToAppear() {
this.refreshConfigurator
.setHasRefresh(true)// 是否具有下拉刷新功能
.setHasLoadMore(true)// 是否具有上拉加载功能
.setMaxTranslate(150)// 可下拉上拉的最大距离
.setSensitivity(1)// 下拉上拉灵敏度
.setListIsPlacement(false)// 滑动结束后列表是否归位
.setAnimDuration(300)// 滑动结束后,回弹动画执行时间
.setRefreshHeight(50)// 下拉动画高度
.setRefreshColor('#638EEF')// 下拉动画颜色
.setRefreshBackgroundColor($r('app.color.home_bg'))// 下拉动画区域背景色
.setRefreshTextColor('#638EEF')// 下拉加载完毕后提示文本的字体颜色
.setRefreshTextSize(15)// 下拉加载完毕后提示文本的字体大小
.setRefreshAnimDuration(1000)// 下拉动画执行一次的时间
.setLoadImgHeight(50)// 上拉图片高度
.setLoadBackgroundColor($r('app.color.home_bg'))// 上拉动画区域背景色
.setLoadTextColor('#638EEF')// 上拉文本的字体颜色
.setLoadTextSize(15)// 上拉文本的字体大小
.setLoadTextPullUp1('请继续上拉...')// 上拉1阶段文本
.setLoadTextPullUp2('释放即可刷新')// 上拉2阶段文本
.setLoadTextLoading('加载中...') // 上拉加载更多中时的文本
// .setRefreshCompleteTextHoldTime(500) //上拉刷新后停留的时间, 默认一秒, 建议设置500
this.fetchWallpapers(this.currentPage)
}
//根据当前页面查找数据源(typeID=>类型id)
private fetchWallpapers(pageNum: number = 1) {
weatherApi.wallpaperList(this.typeID, pageNum, this.pageSize).then(wallpaperListBean => {
this.wallpaperUrlList = wallpaperListBean.data.list // Assuming your API structure
this.dataSource.clear() // Clear the old data
for (let index = 0; index < this.wallpaperUrlList.length; index++) {
this.dataSource.pushData(this.wallpaperUrlList[index].imgUrl)
}
}).catch(error => {
console.error("Error fetching wallpapers:", error)
})
}
build() {
Column() {
PullToRefresh({
// 必传项,需绑定传入主体布局内的列表或宫格组件
scroller: this.scroller,
// 必传项,自定义主体布局,内部有列表或宫格组件
customList: () => {
// 一个用@Builder修饰过的UI方法
this.getListView()
},
refreshConfigurator:this.refreshConfigurator,
mWidth:'100%',
mHeight:'100%',
// 可选项,下拉刷新回调
onRefresh: () => {
return new Promise<string>((resolve, reject) => {
// 网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
this.fetchWallpapers(1) // Fetch first page data
this.currentPage = 1 // Reset the page count
this.timer = setTimeout(() => {
resolve('刷新成功')
console.log(' 刷新成功')
}, 2000)
})
},
// 可选项,上拉加载更多回调
onLoadMore: () => {
return new Promise<string>((resolve, reject) => {
// 网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
this.currentPage++; // Increment the page number
this.fetchWallpapers(this.currentPage); // Fetch the next page of data
this.timer = setTimeout(() => {
resolve('上拉加载完成')
console.log('上拉加载完成')
}, 2000)
})
},
customLoad: null,
customRefresh: null,
})
}
.width('100%')
.height('100%')
}
@Builder
private getListView() {
Grid(this.scroller) {
LazyForEach(this.dataSource, (item, index) => {
GridItem() {
// 显示网络图片
Image(item || $r('app.color.color_white_f0f8'))
.width('100%')
.height('20%')
.alt($r('app.color.color_white_f0f8'))
.borderRadius(8)
.onAppear(() => { //组件挂载显示触发
if (index) {
console.log("Loading onAppear: index=" + item + ' content= ' + this.dataSource.getData(index));
}
})
.onDisAppear(() => { //组件卸载载显示触发
if (index) {
console.log("Loading onDisAppear: index=" + index + ' content= ' + this.dataSource.getData(index));
}
})
.onClick(() => this.handleImageClick(item)); // 注册点击事件
}
}, (item: string) => item)
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(15)
.rowsGap(10)
.cachedCount(10)
.margin({top:15})
.layoutDirection(GridDirection.Row)
.width('90%')
.height('100%')
}
aboutToDisappear() {
clearTimeout(this.timer)
this.dataSource.clear()
}
// 处理点击事件
handleImageClick(imageUrl: string) {
router.pushUrl({
url: "pages/WallpaperDetailsPage",
params: {
imageUrl: imageUrl
}
})
}
}
注意:在api9 开发的时候注意以下两点
1,依赖PullToRefresh 中
@Link data: Object[] 改==》 @State data: Object[]=[];
不然使用的时候PullToRefresh 会报:'@Link' decorated 'data' must be initialized through the component constructor. <ArkTSCheck>
2,同样的在PullToRefresh中找到 this.scroller.isAtEnd(),注释掉,api9 中找不到 this.scroller.isAtEnd()方法