【Harmony】鸿蒙自定义刷新控件 BaseRefresh

介绍

一个功能强大的下拉刷新和加载更多组件,支持自定义刷新样式、空页面展示、加载更多状态、头布局和尾布局。组件内置了基础的刷新动画、状态管理和数据管理,可以轻松实现列表的刷新和加载功能。

功能特点

  • 支持下拉刷新与上拉加载更多功能
  • 支持分页加载和数据管理
  • 适配List/Grid/ScrollView/WaterFlow四种布局类型,也可以自行实现
  • 内置空布局视图:可传入空布局参数改变空布局样式
  • 支持自定义空布局
  • 支持自定义刷新样式和加载更多样式
  • 头部/尾部扩展:支持自定义Header/Footer布局
  • 支持页面数据不满一屏时自动触发上拉加载(需要手动开启)
  • 支持数据分组,支持吸顶/吸尾
  • 支持侧滑功能,包括左侧滑/右侧滑
  • 兼容 V2 状态(该控件是 V2 控件)

链接

源码

示例

效果图

下拉刷新 加载更多 瀑布流布局 网格布局 尾布局 头布局 滚动布局 自定义空布局

下载安装

在每个har/hsp模块中,通过ohpm工具下载安装库:

ohpm install @hzw/zrefresh

使用方法

基本使用示例

  // BaseRefreshController用于更新刷新状态
  @Local controller: BaseRefreshController = new BaseRefreshController()
// BaseRefreshDataSource用于更新数据
  @Local data: BaseRefreshDataSource<String> = new BaseRefreshDataSource<String>()

  aboutToAppear() {
    this.controller.autoRefresh()
  }

  BaseRefresh({
    data: this.data, // 设置数据源
    controller: this.controller, // 设置状态管理
    type: BaseRefreshType.List, // 刷新内容类型,默认为滚动布局
    onRefresh: this.onRefresh, // 设置下拉刷新回调
    onLoadMore: this.onLoadMore, // 设置加载更多回调
    pageSize: 10, // 设置每页加载数量
    refreshModifier: new RefreshModifier(), // 设置Refresh样式
    listModifier: new ListModifier(), // 设置列表样式
    isShowHeader: false, // 设置是否显示头部布局
    isShowFooter: false, // 设置是否显示底部布局
    emptyStatus: {}, // 设置默认空布局样式,如果设置了,则数据为空时会显示默认布局
    customEmptyView: () => { // 设置自定义空布局,如果设置了,则数据为空时会显示自定义布局
      this.Empty()
    },
    customHeadView: () => { // 设置自定义头部布局
      this.Head()
    },
    customFootView: () => { // 设置自定义底部布局
      this.Footer()
    },
    customRefreshHeadView: () => { // 自定义刷新头布局
      this.RefreshHead()
    },
    customRefreshFootView: () => { // 自定义底部加载更多布局
      this.RefreshFoot()
    },
    builder: () => { // 内容
      this.Content()
    },

  })

相关方法

触发刷新
// this.controller 是 BaseRefreshController 的实例
this.controller.autoRefresh()
添加数据
// this.data 是 BaseRefreshDataSource 的实例
this.data.complete(moreData)
结束下拉刷新/结束加载更多
this.controller.finishRefresh()
// 根据数据数量判断是否没有更多数据
const data = ["1", "2"]
this.controller.finishRefresh(data)
// 也可以传入参数来手动设置是否没有更多数据
this.controller.finishRefresh(noMore)
结束下拉刷新
this.controller.finishRefresh()
// 根据数据数量判断是否没有更多数据
const data = ["1", "2"]
this.controller.finishRefresh(data)
// 也可以传入参数来手动设置是否没有更多数据
this.controller.finishRefresh(noMore)
结束加载更多
this.controller.finishLoadMore()
// 根据数据数量判断是否没有更多数据
const data = ["1", "2"]
this.controller.finishLoadMore(data)
// 也可以传入参数来手动设置是否没有更多数据
this.controller.finishLoadMore(noMore)
空页面显示隐藏,不传默认显示
this.controller.showEmpty(visible)
头布局显示隐藏,不传默认显示
this.controller.showHead(visible)
底布局显示隐藏,不传默认显示
this.controller.showFoot(visible)
底部加载更多布局显示隐藏,不传默认显示
this.controller.showRefreshFooter(visible)
重置状态
this.controller.resetStatus()

关于 List(列表) 的刷新示例,通过BaseRefreshController的实例的complete()方法设置数据

@ComponentV2
export struct RefreshListDemo {
  @Local controller: BaseRefreshController = new BaseRefreshController()
  @Local data: BaseRefreshDataSource<String> = new BaseRefreshDataSource<String>()
  @Local emptyData: boolean = false
  @Local pageSize: number = 15

  aboutToAppear() {
    this.controller.autoRefresh()
  }

  onRefresh = () => {
    this.loadData()
  }
  onLoadMore = () => {
    this.loadData()
  }

  loadData() {
    setTimeout(() => {
      if (this.emptyData) {
        this.data.complete([])
        this.controller.finishState([])
        return
      }

      const arr: number[] = []
      const start = (this.controller.pageIndex - 1) * this.pageSize
      if (this.controller.pageIndex == 2) {
        for (let i = start; i < start + 5; i++) {
          arr.push(i)
        }
      } else {
        for (let i = start; i < start + this.pageSize; i++) {
          arr.push(i)
        }
      }
      const result = Array.from(arr, (item, i) => `Item ${item + 1}`)

      this.data.complete(result)
      this.controller.finishState(result)
      return undefined
    }, 700)
  }

  build() {
    BaseRefresh({
      data: this.data, // 设置数据源
      controller: this.controller, // 设置状态管理
      type: BaseRefreshType.List, // 刷新内容类型,默认为滚动布局,当前设置为列表类型
      onRefresh: this.onRefresh, // 设置下拉刷新回调
      onLoadMore: this.onLoadMore, // 设置加载更多回调
      pageSize: this.pageSize, // 设置每页加载数量
      refreshModifier: new RefreshModifier(), // 设置Refresh样式
      listModifier: new ListModifier(), // 设置列表样式
      builder: () => { // 内容
        this.Content()
      },

    })
  }

  @Builder
  Content() {
    LazyForEach(this.data, (item: string) => {
      ListItem() {
        Stack() {
          Text(`${item}`)
            .borderRadius(10)
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .width('100%')
            .height('100%')
            .textAlign(TextAlign.Center)
            .backgroundColor(Color.Blue)
        }
        .width('100%')
        .height(100)
        .padding({ left: 10, right: 10, top: 10 })
      }
    }, (item: string, index: number) => `${item}${index}`)
  }
}

关于 Scroll(滚动) 的刷新示例

@ComponentV2
export struct RefreshScrollDemo {
  @Local controller: BaseRefreshController = new BaseRefreshController()
  @Local emptyData: boolean = false

  aboutToAppear() {
    this.controller.autoRefresh()
  }

  onRefresh = () => {
    this.loadData()
  }
  onLoadMore = () => {
    this.loadData()
  }

  loadData() {
    setTimeout(() => {
      this.controller.showEmpty(this.emptyData)

      this.controller.finishRefresh()
      return undefined
    }, 700)
  }

  build() {
    Column() {
      OperateView({
        controller: this.controller,
        emptyData: this.emptyData!!
      })
      BaseRefresh({
        controller: this.controller, // 设置状态管理
        type: BaseRefreshType.ScrollView, // 刷新内容类型,默认为滚动布局,当前设置为滚动类型
        onRefresh: this.onRefresh, // 设置下拉刷新回调
        onLoadMore: this.onLoadMore, // 设置加载更多回调
        refreshModifier: new RefreshModifier(), // 设置Refresh样式
        scrollModifier: new ScrollModifier(), // 设置滚动样式
        isShowHeader: false, // 设置是否显示头部布局
        isShowFooter: false, // 设置是否显示底部布局
        emptyStatus: {}, // 设置默认空布局样式,如果设置了,则数据为空时会显示默认布局
        customEmptyView: () => { // 设置自定义空布局,如果设置了,则数据为空时会显示自定义布局
          this.Empty()
        },
        customHeadView: () => { // 设置自定义头部布局
          this.Head()
        },
        customFootView: () => { // 设置自定义底部布局
          this.Footer()
        },
        customRefreshHeadView: () => { // 自定义刷新头布局
          this.RefreshHead()
        },
        customRefreshFootView: () => { // 自定义底部加载更多布局
          this.RefreshFoot()
        },
        builder: () => { // 内容
          this.Content()
        },

      })
        .width('100%')
        .layoutWeight(1)
    }
    .width('100%')
      .height('100%')
      .backgroundColor(Color.White)
  }

  @Builder
  Content() {
    Stack() {
      Text(`滚动内容`)
        .borderRadius(10)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
        .width('100%')
        .height('120%')
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.Orange)
    }
    .padding({ left: 10, right: 10, top: 10 })
  }

  @Builder
  Empty() {
    CustomEmpty()
  }

  @Builder
  Head() {
    CustomHead()
  }

  @Builder
  Footer() {
    CustomFooter()
  }

  @Builder
  RefreshHead() {
    CustomRefreshHead()
  }

  @Builder
  RefreshFoot() {
    CustomRefreshFoot({ showEnd: this.controller.showEnd })
  }
}

关于 Grid(网格) 的刷新示例

@ComponentV2
export struct RefreshGridDemo {
  @Local controller: BaseRefreshController = new BaseRefreshController()
  @Local data: BaseRefreshDataSource<String> = new BaseRefreshDataSource<String>()
  @Local emptyData: boolean = false
  @Local col: number = 2
  @Local pageSize: number = 15

  @Computed
  get colStr() {
    const arr: string[] = []
    for (let i = 0; i < this.col; i++) {
      arr.push('1fr')
    }
    return arr.join(' ')
  }

  aboutToAppear() {
    this.controller.autoRefresh()
  }

  onRefresh = () => {
    this.loadData()
  }
  onLoadMore = () => {
    this.loadData()
  }

  loadData() {
    setTimeout(() => {
      if (this.emptyData) {
        this.data.complete([])
        this.controller.finishState([])
        return
      }

      const arr: number[] = []
      const start = (this.controller.pageIndex - 1) * this.pageSize
      if (this.controller.pageIndex == 2) {
        for (let i = start; i < start + 5; i++) {
          arr.push(i)
        }
      } else {
        for (let i = start; i < start + this.pageSize; i++) {
          arr.push(i)
        }
      }
      const result = Array.from(arr, (item, i) => `Item ${item + 1}`)

      this.data.complete(result)
      this.controller.finishState(result)
      return undefined
    }, 700)
  }

  build() {
    BaseRefresh({
      data: this.data, // 设置数据源
      controller: this.controller, // 设置状态管理
      type: BaseRefreshType.Grid, // 刷新内容类型,默认为滚动布局,当前设置为网格类型
      onRefresh: this.onRefresh, // 设置下拉刷新回调
      onLoadMore: this.onLoadMore, // 设置加载更多回调
      pageSize: this.pageSize, // 设置每页加载数量
      refreshModifier: new RefreshModifier(), // 设置Refresh样式
      gridModifier: new GridModifier().columnsTemplate(this.colStr), // 设置网格样式
      builder: () => { // 内容
        this.Content()
      },
    })
  }

  @Builder
  Content() {
    LazyForEach(this.data, (item: string) => {
      GridItem() {
        Stack() {
          Text(`${item}`)
            .borderRadius(10)
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .width('100%')
            .height('100%')
            .textAlign(TextAlign.Center)
            .backgroundColor(Color.Blue)
        }
        .width('100%')
          .height(100)
          .padding({ left: 10, right: 10, top: 10 })
      }
    }, (item: string, index: number) => `${item}${index}`)
  }
}

关于 WaterFlow(瀑布流) 的刷新示例

@ComponentV2
export struct RefreshWaterFlowDemo {
  @Local controller: BaseRefreshController = new BaseRefreshController()
  @Local data: BaseRefreshDataSource<String> = new BaseRefreshDataSource<String>()
  @Local emptyData: boolean = false
  @Local col: number = 2
  @Local pageSize: number = 15

  @Computed
  get colStr() {
    const arr: string[] = []
    for (let i = 0; i < this.col; i++) {
      arr.push('1fr')
    }
    return arr.join(' ')
  }

  aboutToAppear() {
    this.controller.autoRefresh()
  }

  onRefresh = () => {
    this.loadData()
  }
  onLoadMore = () => {
    this.loadData()
  }

  loadData() {
    setTimeout(() => {
      if (this.emptyData) {
        this.data.complete([])
        this.controller.finishState([])
        return
      }

      const arr: number[] = []
      const start = (this.controller.pageIndex - 1) * this.pageSize
      if (this.controller.pageIndex == 2) {
        for (let i = start; i < start + 5; i++) {
          arr.push(i)
        }
      } else {
        for (let i = start; i < start + this.pageSize; i++) {
          arr.push(i)
        }
      }
      const result = Array.from(arr, (item, i) => `Item ${item + 1}`)

      this.data.complete(result)
      this.controller.finishState(result)
      return undefined
    }, 700)
  }

  build() {
    BaseRefresh({
      data: this.data, // 设置数据源
      controller: this.controller, // 设置状态管理
      type: BaseRefreshType.WaterFlow, // 刷新内容类型,默认为滚动布局,当前设置为瀑布流类型
      onRefresh: this.onRefresh, // 设置下拉刷新回调
      onLoadMore: this.onLoadMore, // 设置加载更多回调
      pageSize: this.pageSize, // 设置每页加载数量
      refreshModifier: new RefreshModifier(), // 设置Refresh样式
      scrollModifier: new ScrollModifier(), // 设置滚动样式,因为瀑布流类型是 Scroll嵌套WaterFlow来实现头尾布局,所以用到了Scroll控件
      waterFlowModifier: new WaterFlowModifier().columnsTemplate(this.colStr), // 设置瀑布流样式
      builder: () => { // 内容
        this.Content()
      },
    })
  }

  @Builder
  Content() {
    LazyForEach(this.data, (item: string, index: number) => {
      FlowItem() {
        Stack() {
          Text(`${item}`)
            .borderRadius(10)
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .width('100%')
            .height('100%')
            .textAlign(TextAlign.Center)
            .backgroundColor(Color.Blue)
        }
        .height(Math.random() * 100 + 100)
          .padding({ left: 10, right: 10, top: 10 })
      }
      .width('100%')
    }, (item: string, index: number) => `${item}${index}`)
  }
}

关于 No(不指定滚动布局类型,自行实现) 的刷新示例

@ComponentV2
export struct RefreshNoDemo {
  @Local controller: BaseRefreshController = new BaseRefreshController()
  @Local emptyData: boolean = false

  aboutToAppear() {
    this.controller.autoRefresh()
  }

  onRefresh = () => {
    this.loadData()
  }
  onLoadMore = () => {
    this.loadData()
  }

  loadData() {
    setTimeout(() => {
      this.controller.showEmpty(this.emptyData)

      this.controller.finishRefresh()
      return undefined
    }, 700)
  }

  build() {
    BaseRefresh({
      controller: this.controller, // 设置状态管理
      type: BaseRefreshType.No, // 刷新内容类型,无滚动类型(不内置滚动控件,交由使用者自定义)
      onRefresh: this.onRefresh, // 设置下拉刷新回调
      onLoadMore: this.onLoadMore, // 设置加载更多回调
      refreshModifier: new RefreshModifier(), // 设置Refresh样式
      scrollModifier: new ScrollModifier(), // 设置滚动样式
      builder: () => { // 内容
        this.Content()
      },
    })
  }

  @Builder
  Content() {
    Scroll() {
      Stack() {
        Text(`滚动内容`)
          .borderRadius(10)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .width('100%')
          .height('120%')
          .textAlign(TextAlign.Center)
          .backgroundColor(Color.Orange)
      }
      .padding({ left: 10, right: 10, top: 10 })
    }
  }
}

参数说明

BaseRefresh 组件参数

参数名类型默认值必填说明
dataBaseAbsRefreshDataSource | undefinedundefined数据源,需继承BaseAbsRefreshDataSource
typeBaseRefreshTypeScrollView内容类型:List/ScrollView/Grid/WaterFlow/No
enableRefreshbooleantrue是否启用下拉刷新
enableLoadMorebooleantrue是否启用加载更多
pageSizenumber20每页加载数量
controllerBaseRefreshControllernew BaseRefreshController()状态控制器
scrollerScrollernew Scroller()滚动控制器实例
refreshModifierRefreshModifiernew RefreshModifier()刷新控件样式配置
listModifierListModifiernew ListModifier()列表样式配置
scrollModifierScrollModifiernew ScrollModifier()滚动视图样式配置
gridModifierGridModifiernew GridModifier()网格布局样式配置
waterFlowModifierWaterFlowModifiernew WaterFlowModifier()瀑布流样式配置
listItemModifierListItemModifiernew ListItemModifier()列表项样式配置(需设置listBuilder生效)
onRefresh() => Promise<Object[]|undefined>async () => {}下拉刷新回调函数
onLoadMore() => Promise<Object[]|undefined>async () => {}加载更多回调函数
builder() => voidthis.doBuilder内容构建函数
listBuilder(data: Object, index: number) => voidundefined列表项构建函数(设置后builder属性失效)
swipeLeftBuilder(data: Object, index: number) => voidundefined列表项左滑布局(需设置listBuilder生效)
swipeRightBuilder(data: Object, index: number) => voidundefined列表项右滑布局(需设置listBuilder生效)
isShowHeaderbooleanfalse是否显示头部布局
isShowFooterbooleanfalse是否显示底部布局
isShowRefreshFooterbooleantrue是否显示加载更多布局
groupDataBaseAbsRefreshDataSource | undefinedundefined分组数据源(需设置listBuilder生效)
listItemGroupModifierListItemGroupModifiernew ListItemGroupModifier()列表项分组样式配置(需设置listBuilder和groupData生效)
listItemGroupHeadBuilder(data: BaseRefreshGroupItem, index: number) => voidundefined列表分组头部构建函数(需设置listBuilder和groupData生效)
listItemGroupFootBuilder(data: BaseRefreshGroupItem, index: number) => voidundefined列表分组底部构建函数(需设置listBuilder和groupData生效)
groupStyleListItemGroupStyle | undefinedundefined列表分组样式配置(需设置listBuilder和groupData生效)
isGroupTopStickybooleantrue列表分组是否顶部吸顶(需设置listBuilder和groupData生效)
isGroupFootStickybooleanfalse列表分组是否底部吸顶(需设置listBuilder和groupData生效)
isAutoLoadMoreWhileNoFullbooleanfalse页面数据不满一屏时是否自动触发上拉加载
customEmptyView() => voidundefined自定义空布局组件
customHeadView() => voidundefined自定义头部布局
customFootView() => voidundefined自定义底部布局
customRefreshHeadView() => voidundefined自定义刷新头部组件
customRefreshFootView() => voidundefined自定义加载底部组件
emptyStatusBaseRefreshEmptyStatus | undefinedundefined空布局状态配置
gridLayoutOptionsGridLayoutOptions | undefinedundefined网格布局配置选项

BaseRefreshController 类方法

方法名参数返回值说明
autoRefresh-void自动触发刷新
finishStatenoMore: (Object | undefined | null)[] | undefined | null | booleanvoid根据当前状态结束刷新/加载
finishRefreshnoMore?: (Object | undefined | null)[] | undefined | null | booleanvoid结束刷新状态
finishLoadMorenoMore?: (Object | undefined | null)[] | undefined | null | booleanvoid结束加载更多状态
showEmptyvisible?: boolean控制空页面显示
showHeadvisible?: booleanvoid控制头部布局显示状态
showFootvisible?: booleanvoid控制底部布局显示状态
showRefreshFootervisible?: booleanvoid控制加载更多布局显示状态
resetStatus-void重置所有状态到初始值(包含refreshing/loadMore/showEnd等)
onScrollIndexstart: number, end: numbervoid列表/网格滚动索引变化回调,当滚动到底部时触发加载
onScrollEdgeedge: Edgevoid滚动视图到达边缘回调(Edge.Bottom时触发加载)
onScrollFrameBeginoffset: numberBaseRefreshOffsetInterface滚动偏移量变化回调,用于判定滑动方向

BaseRefreshDataSource 类方法

方法名参数返回值说明
add1stItemdata: Tvoid在列表头部插入元素
addLastItemdata: Tvoid在列表尾部追加元素
addItemindex: number, data: Tvoid在指定位置插入元素
delete1stItem-void删除第一个元素
deleteItemByIndexindex: numbervoid删除指定索引元素
deleteItemdata: Tvoid删除指定元素
setItemindex: number, data: Tvoid更新指定位置元素
clear-void清空所有数据
notifyDataReload-void通知数据重载
notifyDataAddindex: numbervoid通知数据添加事件
notifyDataChangeindex: numbervoid通知数据变更事件
notifyDataDeleteindex: numbervoid通知数据删除事件
completedata: T[] | undefinedvoid完成加载操作(根据刷新状态决定替换或追加数据)

作者其他库

  • 鸿蒙数据库工具:https://gitee.com/HW-Commons/ZDbUtil

联系我们

欢迎大家提交issue、PR(可以统一收集问题,方便更多人查阅,会第一时间回复处理) ,或进群交流(+v: _hhbin)。

WX20250331 152006
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值