一百天挑战学会HarmanyOS——数据的下拉刷新与上拉加载

349 阅读4分钟

大家好我是牛牛,一名软件开发从业者,无意中接触到了鸿蒙移动端开发,对鸿蒙操作系统产生了极大的兴趣,作者将从无到有开发出一款鸿蒙原生APP。每天写一篇关于鸿蒙开发的技术文章。欢迎大家踊跃订阅➕关注,文章中有什么不妥之处可以在评论区中指出。

注意:最好是有开发经验的伙伴来阅读系列文章。零基础的同学可以先去了解一下TypeScript从最基本的开发语言进行学起

前言

上一章节《一百天挑战学会HarmanyOS——界面的渲染》中介绍了 ArkUI页面的渲染,其中示例代码中使用了一个跟 scroll 类似的组件 List 组件,上一章节没有进行详细的讲解。如果没有查看到这一章节内容的同学可以先去了解并且实操一下上一章节的内容。有什么疑问的地方大家可以在评论区留言。

本章介绍

本章主要介绍 ArkUI 开发中最常用的场景下拉刷新, 上拉加载,在本章中介绍的内容在实际开发过程当中会高频的使用,所以同学们要牢记本章的内容。下面就让我们开始今天的讲解吧!

List 组件

ArkUIList容器组件也可以实现数据滚动的效果, 这里为什么先介绍 List 组件,因为在本章节介绍的下拉刷新和上拉加载用到了从此组件,所以一起讲解一下。

语法

List(){
  ListItem(){
    
  }
}

注意: 在 List 组件中必须包含 ListItem 子组件才能正常渲染数据,可以理解为每一个 ListItem 对应的就是一条数据。

示例

list

@Entry
@Component
struct ListDemoPage {
  build() {
    Column() {
      List() {
        ListItem() {
          Row() {
            Text('测试数据 List')
          }
          .padding(10)
          .width('100%')
        }
        ListItem() {
          Row() {
            Text('测试数据 List')
          }
          .padding(10)
          .width('100%')
        }
        ListItem() {
          Row() {
            Text('测试数据 List')
          }
          .padding(10)
          .width('100%')
        }
        ListItem() {
          Row() {
            Text('测试数据 List')
          }
          .padding(10)
          .width('100%')
        }
        ListItem() {
          Row() {
            Text('测试数据 List')
          }
          .padding(10)
          .width('100%')
        }
      }
      .height(100)
      .divider({strokeWidth:1,color:"#ededed"})
    }
    .height('100%')
    .width('100%')
  }
}

我们发现当页面元素超出了List组件设置的高度,屏幕上就会出现滚动条,并且下拉画面数据到顶部的时候,画面整体也会被下拉。并且上述代码有重复代码,这时我们就可以使用上一章节讲解的循环渲染ForEach组件去渲染列表让我们改造一下代码。

list1

@Entry
@Component
struct ListDemoPage {

  // 定义一个类型为number,长度为 30 的数组,并且放入数据,数据为当前时间戳
  @State
  data:number[] = new Array(30).fill(Date.now())

  build() {
    Column() {
      // 使用 List 组件
      List() {
        // 循环渲染
        ForEach(this.data,(item:number)=>{
          // 必须使用 ListItem 组件进行包裹
          ListItem() {
            Row() {
              Text(item+"")
            }
            .padding(10)
            .width('100%')
          }
        })

      }
      .height('100%')
      .divider({strokeWidth:1,color:"#ededed"})
    }
    .height('100%')
    .width('100%')
  }
}

下面我们实现下拉刷新添加数据

Refresh 组件

Refresh可以进行页面下拉操作并显示刷新动效的容器组件。Refresh子组件会跟随手势下拉而下移。我们使用这个组件将我们上面的代码进行包裹。

语法

Refresh(){
  
}

介绍一下 可以往Refresh组件传递的参数(先介绍两个)

  • refreshing:当前组件是否正在刷新。支持双向绑定
  • builder:下拉时,自定义刷新样式的组件。可以自定义下拉刷新样式。

下拉刷新

下面让我们使用Refresh组件实现下拉刷新的功能。

示例

list2

@Entry
@Component
struct ListDemoPage {

  // 定义数据
  @State
  data:number[] = new Array(30).fill(Date.now())
  // 定义刷新状态 flag
  @State
  private refreshingFlag: boolean = false;
  // 自定义下刷新页面
  @Builder
  private LoadingCustom() {
    Stack() {
      Row() {
        // Loading 组件
        LoadingProgress().width(30).color("#4095cb")
      }
    }.width('100%')
  }

  build() {
    Column() {
      // 使用刷新组件
      Refresh({ refreshing: $$this.refreshingFlag, builder: this.LoadingCustom() }) {
        List() {
          ForEach(this.data, (item: number) => {
            ListItem() {
              Row() {
                Text(item + "")
              }
              .padding(10)
              .width('100%')
            }
          })

        }
        .height('100%')
        .divider({ strokeWidth: 1, color: "#ededed" })
      }
      // 进入刷新状态时触发回调。这里两后停止刷新状态
      .onRefreshing(() => {
        setTimeout(() => {
          this.refreshingFlag = false
        }, 2000)
      })
      // 设置触发刷新的下拉偏移量。
      .refreshOffset(64)
      // 设置当下拉距离超过refreshOffset时是否触发刷新。
      .pullToRefresh(true)
    }
    .height('100%')
    .width('100%')
  }
}

上述代码中使用@builder 装饰器修饰的内容可以理解为一个子画面,实现了自定义刷新页面,本章先不过多的说@builder 的作用。

现在只需在onRefreshing的方法中新增 List 的数据即可。

 .onRefreshing(() => {
        setTimeout(() => {
          this.refreshingFlag = false
          // 添加数据
          this.data.push(...Array(30).fill(Date.now()))
        }, 2000)
 })

效果:

list3

如上图所示,每次下拉刷新后画面会新增 30 条数据。

上拉加载

Refresh组件中没有提供上拉加载的功能,我们可以结合 List 组件的事件来实现此功能。

示例

list4

我们发现当页面的滚动条触底时,会触发加载数据的事件,此时我们需要在代码中知道当前滚动条的状态。

import { promptAction } from '@kit.ArkUI';

@Entry
@Component
struct ListDemoPage {

  @State
  data:number[] = new Array(30).fill(Date.now())

  @State
  private refreshingFlag: boolean = false;
  // 判断滚动条是否触底
  @State
  private isEnd: boolean = false;
  // 使用Scroller对象
  scroller: Scroller = new Scroller();

  @Builder
  private LoadingCustom() {
    Stack() {
      Row() {
        LoadingProgress().width(30).color("#4095cb")
      }

    }.width('100%')
  }

  build() {
    Column() {
      Refresh({ refreshing: $$this.refreshingFlag, builder: this.LoadingCustom() }) {
        List() {
          ForEach(this.data, (item: number) => {
            ListItem() {
              Row() {
                Text(item + "")
              }
              .padding(10)
              .width('100%')
            }
          })

        }
        .height('100%')
        .divider({ strokeWidth: 1, color: "#ededed" })
        // 当画面能滚动说明没有触底
        .onScrollStart(() => {
          this.isEnd = false
        })
        // 判断当前是否停止滚动
        .onScrollStop(() => {
          // 如果停止滚动并且满足滚动条已经在底部进行数据的加载。
          if (this.isEnd) {
            // 加载数据
            promptAction.showToast({ message: '加载数据' })
            setTimeout(()=>{
              this.data.push(...Array(30).fill(Date.now()))
              // 加载完数据把滚动条移至底部
              this.scroller.scrollEdge(Edge.Bottom)
            },1000)
          }
        })
        // 当滚动条触底把 flag 设置成 true
        .onReachEnd(() => {
          this.isEnd = true
        })
      }
      .onRefreshing(() => {
        setTimeout(() => {
          this.refreshingFlag = false
          this.data.push(...Array(30).fill(Date.now()))
        }, 2000)
      })
      .refreshOffset(64)
      .pullToRefresh(true)
    }
    .height('100%')
    .width('100%')
  }
}

今天这期就到这里啦!文章中的代码已经上传到 项目代码git 仓库,欢迎大家的关注➕点赞➕分享