HarmonyOS 关于列表的加载更多交互替代

我们已经使用Refresh组件实现了列表的下拉刷新,但对于列表的上拉加载更多,似乎并没有再Refresh中有体现,这点有什么替代方案嘛?

HarmonyOS
2024-08-30 09:41:29
浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
zxjiu

有多种选择可供参考:

1.下拉刷新可以用系统组件Refresh,上拉加载自定义实现

2.使用第三方库PullToRefresh,带有下拉刷新和上拉加载。

https://gitee.com/openharmony-sig/PullToRefresh?_from=gitee_search

可以引入三方库 PullToRefresh 来实现 上拉加载和下拉刷新

地址:

https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fpulltorefresh

参考demo

// PullRefreshPage.ets 
import { PullToRefresh } from '@ohos/pulltorefresh' 
@Entry 
@Component 
struct PullRefreshPage { 
 @State refreshText: string = ''; 
 private dataNumbers: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']; 
 private dataStrings: string[] = ['列表item1', '列表item2', '列表item3', '列表item4', '列表item5', '列表item6', '列表item7', '列表item8']; 
 @State data: string[] = this.dataStrings; 
 // 需绑定列表或宫格组件 
 private scroller: Scroller = new Scroller(); 
 
 build() { 
  Column() { 
   PullToRefresh({ 
    // 必传项,列表组件所绑定的数据 
    data: $data, 
    // 必传项,需绑定传入主体布局内的列表或宫格组件 
    scroller: this.scroller, 
    // 必传项,自定义主体布局,内部有列表或宫格组件 
    customList: () => { 
     // 一个用@Builder修饰过的UI方法 
     this.getListView(); 
    }, 
    // 可选项,下拉刷新回调 
    onRefresh: () => { 
     return new Promise<string>((resolve, reject) => { 
      // 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据 
      setTimeout(() => { 
       resolve('刷新成功'); 
       this.data = this.dataNumbers; 
      }, 2000); 
     }); 
    }, 
    // 可选项,上拉加载更多回调 
    onLoadMore: () => { 
     return new Promise<string>((resolve, reject) => { 
      // 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据 
      setTimeout(() => { 
       resolve(''); 
       this.data.push("增加的条目" + this.data.length) 
      }, 2000); 
     }); 
    }, 
    customLoad: null, 
    customRefresh: null, 
   }) 
  } 
 } 
 @Builder 
 private getListView() { 
  List({ space: 20, scroller: this.scroller }) { 
   ForEach(this.data, (item: string) => { 
    ListItem() { 
     Text(item).width('100%').height(150).fontSize(20).textAlign(TextAlign.Center).backgroundColor('#95efd2') 
    } 
   }) 
  } 
  .divider({ strokeWidth: 1, color: 0x222222 }) 
  .edgeEffect(EdgeEffect.None) // 必须设置列表为滑动到边缘无效果 
 } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.

还可以自定义

在页面布局上,主要是List组件内部ForEach循环渲染前面的列表项后,再添加一个ListItem来实现加载更多布局,通过visibility属性控制显隐。

在列表上拉过程中监听并处理onTouch事件,当触发上拉阈值时,请求并加载更多数据,针对加载情况,加载中使用LoadingProgress和Text组件来展示加载中的效果;加载成功则在List后加载新数据;

示例demo:

enum StatusType { 
 SUCCESS, 
 FAIL 
} 
 
@Entry 
@Component 
export default struct UpSlideLoadDemo { 
 @State list: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
 @State offsetY: number = 0 // 列表y坐标偏移量 
 private downY: number = 0 // 按下的y坐标 
 private lastMoveY: number = 0 // 上一次移动的坐标 
 private endIndex: number = 0 // 当前列表尾部索引 
 private loadMoreHeight = 100 // 触发上拉加载的阈值高度 
 
 @State isLoadMore: boolean = false // 是否可以加载更多,上拉加载的布局是否显示 
 private isLoading: boolean = false // 是否加载中:加载中不进入触摸逻辑 
 @State isShowRetry: boolean = false // 点击重试 是否显示 
 
 build() { 
  Column() { 
   List({ space: 20, initialIndex: 0 }) { 
    ForEach(this.list, (item) => { 
     ListItem() { 
      Text('' + item).width('100%').height('100%') 
       .fontSize(24) 
       .textAlign(TextAlign.Center) 
       .borderRadius(10) 
       .backgroundColor(0xDCDCDC) 
     }.width('100%').height(100) 
    }, item => item.toString()) 
 
    // 加载更多布局 
    ListItem() { 
     Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 
      if (this.isShowRetry) { 
       Text('加载失败,点击重试') 
        .margin({ left: 7, bottom: 1 }) 
        .fontColor(Color.Grey) 
        .fontSize(24) 
        .onClick(() => { 
         this.isShowRetry = false 
         this.touchUpLoadMore() 
        }) 
      } else { 
       LoadingProgress() 
        .width(36).height(36) 
 
       Text('正在加载...') 
        .margin({ left: 7, bottom: 1 }) 
        .fontColor(Color.Grey) 
        .fontSize(24) 
      } 
     }.width('100%').height('100%') 
     .backgroundColor(0xFFFFFF) 
 
    } 
    .height(this.loadMoreHeight) 
    .visibility(this.isLoadMore ? Visibility.Visible : Visibility.None) 
 
   } 
   .width('100%') 
   .height('100%') 
   .listDirection(Axis.Vertical) // 排列方向 
   .onScrollIndex((start: number, end: number) => { 
    console.info('start = ' + start.toString() + ' end = ' + end.toString()) 
    this.endIndex = end 
   }) 
   .onTouch(event => this.handleTouchEvent(event)) 
  } 
  .width('100%') 
  .height('100%') 
  .backgroundColor(0xFFFFFF) 
 } 
 
 /** 
  * 处理onTouch事件 
  * @param event 
  */ 
 handleTouchEvent(event: TouchEvent) { 
  switch (event.type) { 
  // 手指按下 
   case TouchType.Down: 
    this.downY = event.touches[0].y; // 记录按下的y坐标 
    this.lastMoveY = event.touches[0].y; 
    break; 
  // 手指滑动 
   case TouchType.Move: 
    if (this.isLoading) { // 更多数据加载中,不进入处理逻辑 
     return; 
    } 
    if (event.touches[0].y - this.lastMoveY < 0) { // 手指上滑 
     // 因为加载更多是在列表后面新增一个item,当一屏能够展示全部列表,endIndex 为 length+1 
     if (this.endIndex == this.list.length - 1 || this.endIndex == this.list.length) { 
 
      this.offsetY = event.touches[0].y - this.downY; // 滑动的偏移量 
 
      if (Math.abs(this.offsetY) > this.loadMoreHeight) { // 数据加载的阈值 
       this.isLoadMore = true // 可以刷新了 
       this.offsetY = this.loadMoreHeight + this.offsetY * 0.1 // 偏移量缓慢增加 
      } 
     } 
    } 
    this.lastMoveY = event.touches[0].y; 
    break; 
  // 手指抬起 
   case TouchType.Up: 
  // 事件取消 
   case TouchType.Cancel: 
    if (this.isLoading) { // 更多数据加载中,不进入处理逻辑 
     return; 
    } 
    this.touchUpLoadMore() 
    break 
  } 
 } 
 
 /** 
  * 手指抬起,处理加载更多 
  */ 
 private touchUpLoadMore() { 
  animateTo({ 
   duration: 300, // 动画时长 
  }, () => { 
   this.offsetY = 0 // 偏移量设置为0 
  }) 
 
  if (this.isLoadMore) { 
   this.isLoading = true // 加载中... 
   setTimeout(() => { // 模拟耗时操作 
    this.getData() 
     .then(data => { 
      if (data === StatusType.SUCCESS) { // 加载成功 
       this.isShowRetry = false 
       this.loadMoreData() // 加载数据 
       // 关闭加载更多 
       this.isLoadMore = false 
       this.isLoading = false 
      } 
     } 
 
    /** 
     * mock 产生更多数据 
     */ 
    private loadMoreData() { 
     let initValue = this.list[this.list.length - 1] + 1; 
     for (let i = initValue; i < initValue + 10; i++) { 
      this.list.push(i) 
     } 
    } 
 
    /** 
     * 模拟数据加载结果 
     */ 
    private getData(): Promise<StatusType> { 
     return new Promise((resolve, reject) => { 
     const randomNumber: number = Math.random(); 
     if (randomNumber >= 0.5) { 
     resolve(StatusType.SUCCESS) 
    } else { 
     reject(StatusType.FAIL) 
    } 
   }) 
  } 
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
分享
微博
QQ
微信
回复
2024-08-30 17:54:47
相关问题
刷新列表加载更多问题
1060浏览 • 1回复 待解决
HarmonyOS 列表联动交互
513浏览 • 1回复 待解决
HarmonyOS 上拉加载更多
607浏览 • 1回复 待解决
HarmonyOS swiper实现上拉加载更多
656浏览 • 1回复 待解决
HarmonyOS 下拉聊天数据加载更多实现
776浏览 • 1回复 待解决
HarmonyOS webview加载交互
827浏览 • 1回复 待解决