HarmonyOS 关于列表的加载更多交互替代-鸿蒙开发者社区-51CTO.COM

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) // 必须设置列表为滑动到边缘无效果 
 } 
}

还可以自定义

在页面布局上,主要是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) 
    } 
   }) 
  } 
 }
分享
微博
QQ
微信
回复
2024-08-30 17:54:47
相关问题
刷新列表加载更多问题
259浏览 • 1回复 待解决
HarmonyOS 列表展示list懒加载问题
502浏览 • 1回复 待解决
关于获取应用列表权限问题?
3414浏览 • 1回复 待解决
关于权限列表条目缺少问题
1924浏览 • 1回复 待解决
ImageReader 在HarmonyOS替代方案
1544浏览 • 1回复 待解决
使用LazyForEach懒加载列表相关问题
810浏览 • 1回复 待解决
关于Image组件加载网络图片问题
422浏览 • 1回复 待解决
关于自定义XComponent加载so问题
71浏览 • 1回复 待解决
SpannableString有替代吗?
6038浏览 • 1回复 待解决