HarmonyOS中实现上拉加载下拉刷新

参考网址:Refresh-滚动与滑动-ArkTS组件-ArkUI(方舟UI框架)-应用框架 - 华为HarmonyOS开发者

1.数据基类

//根据自己的业务数据扩展此类
//注意:一定要继承Object
export class PullToRefreshBean extends Object{
  name: string = ''
  num: number = 0
  //一定要写构造,不然取不到数据
  constructor(name: string, num: number) {
    super()
    this.name = name
    this.num = num
  }
}

2.PullToRefreshListener监听器

export interface PullToRefreshListener{
  loadMore: () => void;//监听加载更多
  refresh: () => void//监听数据刷新
  //错误写法:(这种写法应该是把方法当成了属性来实现)
  //loadMore(): void;
  //refresh(): void;
}

3.PullToRefreshView刷新组件(相当于Android中自定义控件)

import { PullToRefreshListener } from "../ViewModel/PullToRefreshListener";


@Component
export struct PullToRefreshView{
  @Link arr: Array<Object>
  @Link refreshing: boolean
  @State refreshOffset: number = 0;
  @State refreshState: RefreshStatus = RefreshStatus.Inactive;
  @State canLoad: boolean = false;
  @Link isLoading: boolean

  @Prop listener: PullToRefreshListener
  @Builder listItem(item: Object) {}
  @BuilderParam item: (item: Object) => void = this.listItem

  //头部刷新
  @Builder
  refreshBuilder() {
    Stack({ alignContent: Alignment.Bottom }) {
      // 可以通过刷新状态控制是否存在Progress组件
      // 当刷新状态处于下拉中或刷新中状态时Progress组件才存在
      if (this.refreshState != RefreshStatus.Inactive && this.refreshState != RefreshStatus.Done) {
        //转圈加载
        // Progress({ value: this.refreshOffset, total: 64, type: ProgressType.Ring })
        //   .width(32).height(32)
        //   .style({ status: this.refreshing ? ProgressStatus.LOADING : ProgressStatus.PROGRESSING })
        //   .margin(10)
        Row() {
          LoadingProgress().height(32).width(48)
          Text("正在刷新...")
        }.width("100%")
        .height(64)
        .justifyContent(FlexAlign.Center)
      }
    }
    .clip(true)
    .height("100%")
    .width("100%")
  }
  //底部加载
  @Builder
  footer() {
    Row() {
      LoadingProgress().height(32).width(48)
      Text("加载中...")
    }.width("100%")
    .height(64)
    .justifyContent(FlexAlign.Center)
    // 当不处于加载中状态时隐藏组件
    .visibility(this.isLoading ? Visibility.Visible : Visibility.Hidden)
  }

  build() {
    Refresh({ refreshing: $$this.refreshing, builder: this.refreshBuilder() }) {
      List() {
        //ForEach中不加index: number,会出只显示一条数据
        ForEach(this.arr, (item: Object, index: number) => {
          this.item(item)
        }, (item: Object, index: number) => index.toString())
        ListItem() {
          this.footer();
        }
      }
      .onScrollIndex((start: number, end: number) => {
        // 当达到列表末尾时,触发新数据加载
        if (this.canLoad && end >= this.arr.length - 1) {
          this.canLoad = false;
          this.isLoading = true;
          // 数据加载监听
          this.listener.loadMore()
        }
      })
      .onScrollFrameBegin((offset: number, state: ScrollState) => {
        // 只有当向上滑动时触发新数据加载
        if (offset > 5 && !this.isLoading) {
          this.canLoad = true;
        }
        return { offsetRemain: offset };
      })
      .scrollBar(BarState.Off)
      // 开启边缘滑动效果
      .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(0xDCDCDC)
    .onOffsetChange((offset: number) => {
      this.refreshOffset = offset;
    })
    .onStateChange((state: RefreshStatus) => {
      this.refreshState = state;
    })
    .onRefreshing(() => {
      //刷新监听
      this.listener.refresh()
    })
  }
}

4.组件中使用

import {PullToRefreshView } from "./PullToRefreshView";
import { PullToRefreshListener } from "../ViewModel/PullToRefreshListener";
import { PullToRefreshBean } from "../constants/PullToRefreshBean";

@Entry({routeName: 'IndexPage'})

@Component
export struct IndexPage{
  @State arr: Array<PullToRefreshBean> = [];
  @State refreshing: boolean = false;
  @State isLoading: boolean = false;

  //生命周期方法,在build方法之前
  aboutToAppear(): void {
    //console.log(`上一个界面传过来的参数:${(router.getParams() as ParamsBean).name}`)
    //接口调数据(此处是测试数据)
    for (let index = 0; index < 10; index++) {
      this.arr.push(new PullToRefreshBean(`${index}`, index))
    }
  }
  @Builder
  listItem(item: Object) {
    ListItem() {
      //列表条目组件布局,根据业务需求自己扩展,此处也可以提取到子组件中(为了代码简洁和解耦)
      Text('' + (item as PullToRefreshBean).name)
        .width('100%')
        .height(80)
        .fontSize(16)
        .textAlign(TextAlign.Center)
        .backgroundColor(0xFFFFFF)
    }.borderWidth(1)
    .onClick(() => {
      //列表条目点击事件监听
      console.log('我点击的条目是:'+item)
    })
  }

  @State listener: PullToRefreshListener = {
    loadMore: (): void => {
      console.log('加载数据')
      setTimeout(() => {
        let a = this.arr.length-1
        for (let index = a; index < a+10; index++) {
          this.arr.push(new PullToRefreshBean(`${index}`, index))
        }
        this.isLoading = false;
      }, 2000)
    },
    refresh: (): void => {
      console.log('刷新数据');
      setTimeout(() => {
        this.refreshing = false;
      }, 2000)
    }
  }
  build() {
    Column(){
      PullToRefreshView({
        arr: this.arr,
        item: this.listItem,
        listener: this.listener,
        refreshing: this.refreshing,
        isLoading: this.isLoading
      })
    }
  }
}

说明:我是根据官网提供的Refresh实例代码封装的简单使用(代码可直接使用),各位大神有其他酷炫的效果可以交流交流!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值