效果图:
一:下载安装(地址: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 = nullprivate 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) //上拉刷新后停留的时间, 默认一秒, 建议设置500this.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 structurethis.dataSource.clear() // Clear the old datafor (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 datathis.currentPage = 1 // Reset the page countthis.timer = setTimeout(() => {resolve('刷新成功')console.log(' 刷新成功')}, 2000)})},// 可选项,上拉加载更多回调onLoadMore: () => {return new Promise<string>((resolve, reject) => {// 网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据this.currentPage++; // Increment the page numberthis.fetchWallpapers(this.currentPage); // Fetch the next page of datathis.timer = setTimeout(() => {resolve('上拉加载完成')console.log('上拉加载完成')}, 2000)})},customLoad: null,customRefresh: null,})}.width('100%').height('100%')}@Builderprivate 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()方法