Skip to content

上拉下拉刷新组件 - RefreshList

鸿蒙HarmonyOS NEXT 简单易用的上拉下拉刷新组件,支持自定义样式和多种使用场景,兼容API 15+。

如果项目对你有帮助,欢迎持续关注和 🌟Star💖赞助

特性

  • 支持下拉刷新和上拉加载更多
  • 支持自定义刷新头部和底部组件
  • 支持自定义加载中和空页面组件
  • 支持自定义 HeaderView 组件
  • 支持分组列表
  • 支持全局自定义各种组件
  • 完善的 demo 示例

安装

通过 ohpm 安装

bash
ohpm install @cxy/refreshlist

通过依赖安装

在项目的 oh-package.json5 文件中添加依赖, 然后执行同步操作:

json5
{
  "dependencies": {
    "@cxy/refreshlist": "^1.0.4"
  }
}

Demo - 前往查看示例代码

demo.jpeg
Demo 页面
simple.gif
简单示例
group.gif
分组示例
headerview.gif
自定义HeaderView示例
custom.gif
各种自定义示例
chat.gif
聊天示例
dynamic.gif
动态刷新示例
infinite.gif
无限加载示例
search.gif
搜索示例
grid.gif
网格示例

advanced.gif
高级使用示例
global.gif
全局配置示例

快速开始

typescript
import { RefreshController, RefreshDataSource, RefreshList } from "@cxy/refreshlist"

// 1. 创建数据模型
class ItemModel {
  id: string = ''
  title: string = ''

  constructor(id: string = '', title: string = '') {
    this.id = id
    this.title = title
  }
}

// 2. 创建ViewModel
class SimpleViewModel {
  @Track dataSource: RefreshDataSource = new RefreshDataSource()
  @Track controller: RefreshController = new RefreshController()
  private currentPage: number = 1
  private pageSize: number = 20

  refresh(): void {
    this.requestData(1)
  }

  loadMore(): void {
    this.requestData(this.currentPage + 1)
  }

  private async requestData(page: number): Promise<void> {
    // 模拟网络请求延迟
    setTimeout(() => {
      this.currentPage = page
      const data = this.generateSimpleData(this.pageSize)
      if (page === 1) {
        this.dataSource.deleteAll()
      }
      this.dataSource.pushDataArray(data)

      // 模拟最多5页数据
      const hasMore = page < 5
      this.controller.setHasmore(hasMore)
      this.controller.finishRefresh()
    }, 500)
  }

  private generateSimpleData(count: number): ItemModel[] {
    const result: ItemModel[] = []
    for (let i = 0; i < count; i++) {
      const globalIndex = (this.currentPage - 1) * this.pageSize + i
      const item = new ItemModel(`simple_${globalIndex}`, `Title - ${globalIndex + 1}`)
      result.push(item)
    }
    return result
  }
}


// 3. 使用组件
@Entry
@Component
struct Index {
  @State viewModel: SimpleViewModel = new SimpleViewModel()

  aboutToAppear() {
    this.viewModel.refresh()
  }

  build() {
    Column() {
      RefreshList({
        dataSource: this.viewModel.dataSource,
        controller: this.viewModel.controller,
        onRefresh: () => this.viewModel.refresh(),
        onLoadMore: () => this.viewModel.loadMore(),
        itemLayout: (item: Object, index: number) => this.itemLayout(item as ItemModel),
        divider: { strokeWidth: 0.5, color: '#f0f0f0' },
        keyGenerator: (item: ItemModel) => item.id
      })
    }
  }

  @Builder
  itemLayout(item: ItemModel): void {
    ListItem() {
      Row() {
        Text(item.title)
          .fontSize(16)
          .fontColor('#333')
          .fontWeight(FontWeight.Medium)
          .layoutWeight(1)

        Image($r('sys.media.ohos_ic_public_arrow_right'))
          .width(16)
          .height(16)
          .fillColor('#ccc')
      }
      .width('100%')
        .padding(16)
        .backgroundColor('#fff')
    }
    .onClick(()=> {
      console.log(`点击项目: ${ item.title}`)
    })
  }
}

就是这么简单! 三步即可拥有一个功能完整的刷新列表。

API 文档

RefreshList 组件属性

必需属性

属性类型说明
dataSourceRefreshDataSource | RefreshGroupDataSource数据源,管理列表数据
controllerRefreshController控制器,用于控制刷新状态和列表操作

布局属性

属性类型默认值说明
itemLayout(item: Object, index: number) => void-列表项布局
customLayout() => void-自定义布局,完全自定义LazyForEach部分
headerLayout() => void-列表头部布局,类似iOS的tableHeaderView
loadingLayout() => void默认加载视图加载中状态的布局
emptyLayout() => void默认空视图空数据状态的布局
refreshHeaderLayout() => void默认刷新头部自定义下拉刷新头部布局
refreshFooterLayout() => void默认刷新底部自定义上拉加载底部布局

数据状态属性

属性类型默认值说明
refreshHeaderDataRefreshHeaderData-下拉刷新头部数据,用于自定义刷新头部状态
refreshFooterDataRefreshFooterData-上拉加载底部数据,用于自定义加载底部状态
showLoadingbooleantrue是否显示加载状态
showEmptybooleantrue是否显示空数据状态

列表配置属性

属性类型默认值说明
cachedCountnumber4缓存的列表项数量,用于性能优化
showLoadMoreGreaterCountnumber5当item大于多少时,才显示加载更多组件,通常为一屏能显示的item数量
contentStartOffsetnumber-设置内容区域起始偏移量
contentEndOffsetnumber-设置内容区末尾偏移量
stickyStickyStyleStickyStyle.Header | Footer吸顶样式
itemSpacenumber-列表项间距
barStateBarStateBarState.On滚动条状态
scrollBarColorColor | number | string-滚动条颜色
nestedScrollNestedScrollOptions-设置前后两个方向的嵌套滚动模式,实现与父组件的滚动联动
enableScrollInteractionboolean-设置是否支持滚动手势
pullDownRationumber-设置下拉跟手系数,禁止下拉设置0
refreshOffsetnumber-设置触发刷新的下拉偏移量
dividerRefreshListDividernull分割线样式
lanesnumber-设置List组件的布局列数或行数(网格布局)
gutterDimension-列间距(网格布局时使用)
maintainVisibleContentPositionbooleanfalse插入或删除数据时是否保持可见内容位置不变
backToTopbooleantrue设置滚动组件是否支持点击状态栏回到顶部(API version 15+)
edfeEffectEdgeEffect-List的EdgeEffect效果
listAttrModifierRefreshListAttrModifier-用于自定义更多List属性

回调函数

属性类型说明
onRefresh() => void下拉刷新时的回调函数
onLoadMore() => void上拉加载更多时的回调函数
keyGenerator(item: ESObject, index: number) => string列表项唯一标识生成器
onDidScrollOnScrollCallback滚动时的回调函数
onReachEnd() => void滚动到底部时的回调函数
onScrollIndex(start: number, end: number) => void滚动到索引时的回调函数,可用于实现无感知预加载

滚动控制器

属性类型说明
scrollerListScroller列表滚动控制器,可用于获取滚动位置等信息和控制滚动

RefreshController 控制器

RefreshController 提供了控制刷新列表的各种方法:

属性

属性类型说明
scrollerListScroller列表滚动控制器,可用于获取滚动位置等信息和控制滚动

方法

方法参数返回值说明
finishRefresh()void结束刷新状态,必须在刷新完成后调用
setHasmore(hasmore: boolean)void设置是否还有更多数据可加载
hideLoadMore(hide: boolean)void隐藏或显示加载更多组件
onRefresh()void手动触发下拉刷新
scrollToIndex(index: number, smooth?: boolean, align?: ScrollAlign, options?: ScrollToIndexOptions)void滚动到指定索引位置

内部回调属性(由组件自动设置)

属性类型说明
setHasmore(hasmore: boolean) => void设置是否还有更多数据
onRefresh() => void刷新回调
finishRefresh() => void完成刷新回调
hideLoadMore(hide: boolean) => void隐藏加载更多回调
scrollToIndex(value: number, smooth?: boolean, align?: ScrollAlign, options?: ScrollToIndexOptions) => void滚动到指定索引回调

使用示例

typescript
export class SimpleViewModel {
  controller: RefreshController = new RefreshController()

  refresh(): void {
    // 模拟网络请求
    setTimeout(() => {
      // 处理数据...

      // 设置是否还有更多数据
      this.controller.setHasmore(hasMore)

      // 必须调用finishRefresh结束刷新状态
      this.controller.finishRefresh()

    }, 1000)
  }

  // 手动触发刷新
  manualRefresh(): void {
    this.controller.onRefresh()
  }

  // 滚动到顶部
  scrollToTop(): void {
    this.controller.scrollToIndex(0, true)
  }

  // 获取当前滚动位置
  getCurrentOffset(): number {
    return this.controller.scroller.currentOffset().yOffset
  }
}

RefreshDataSource 数据源

RefreshDataSource 是管理列表数据的核心类,实现了 IDataSource 接口:

基础方法

方法参数返回值说明
isEmpty()boolean判断数据源是否为空
totalCount()number获取数据总数 (分组时,为分组数量)
totalItemCount()number获取数据项总数(分组时,为分组下item总数)
getData(index: number)Object | undefined获取指定索引的数据
getLastData()Object | undefined获取最后一项数据
getDataAll()Object[]获取所有数据的副本

数据操作方法

方法参数返回值说明
insertData(index: number, data: Object)void在指定位置插入单个数据
insertDataArray(index: number, arr: Object[])void在指定位置插入数据数组
pushData(data: Object)void在末尾添加单个数据
pushDataArray(arr: Object[])void在末尾添加数据数组
deleteIndex(index: number)void删除指定索引的数据
deleteData(data: Object)void删除指定数据对象
deleteAll()void删除所有数据
deleteIndexCount(index: number, count: number)void从指定索引开始删除指定数量的数据
repalceIndex(index: number, data: Object, key?: string)void替换指定索引的数据
reloadIndex(index: number, key?: string)void重新加载指定索引的数据
reloadData(data: Object, key?: string)void重新加载指定数据对象
reloadDataAll()void重新加载所有数据
moveDataIndex(from: number, to: number)void移动数据从一个位置到另一个位置

监听器方法

方法参数返回值说明
registerDataChangeListener(listener: DataChangeListener)void注册数据变化监听器
unregisterDataChangeListener(listener: DataChangeListener)void取消注册数据变化监听器

回调属性

属性类型说明
onDataCountChange(count: number) => void数据数量变化时的回调

RefreshGroupDataSource 分组数据源

RefreshGroupDataSource 继承自 RefreshDataSource,专门用于管理分组列表数据:

重写方法

方法参数返回值说明
isEmpty()boolean判断分组数据源是否为空
totalItemCount()number计算所有分组中的数据项总数
getGroupDataAll()Object[]获取所有分组中的数据项

分组特有方法

方法参数返回值说明
addListToGroup(list: Object[], getTitle: (e: Object) => string)void将数据列表按标题分组添加

使用示例

typescript
// 基础数据源使用
export class SimpleViewModel {
  dataSource: RefreshDataSource = new RefreshDataSource()

  refresh(): void {
    // 清空现有数据
    this.dataSource.deleteAll()

    // 添加新数据
    const newData = this.generateData()
    this.dataSource.pushDataArray(newData)
  }

  addItem(item: ItemModel): void {
    this.dataSource.pushData(item)
  }

  removeItem(item: ItemModel): void {
    this.dataSource.deleteData(item)
  }

  updateItem(index: number, newItem: ItemModel): void {
    this.dataSource.repalceIndex(index, newItem)
  }
}

// 分组数据源使用
export class GroupViewModel {
  dataSource: RefreshGroupDataSource = new RefreshGroupDataSource()

  refresh(): void {
    this.dataSource.deleteAll()

    const allItems = this.generateData()
    // 按category字段自动分组
    this.dataSource.addListToGroup(allItems, (item) => item.category)
  }
}

RefreshGroupModel 分组模型

分组数据的模型类:

属性

属性类型说明
titlestring分组标题
dataSourceRefreshDataSource分组内的数据源
dataObject可选的附加数据

构造函数

typescript
constructor(title:string, dataSource:RefreshDataSource)

RefreshHeaderData 刷新头部数据

下拉刷新头部的状态数据:

属性类型默认值说明
stateRefreshStatusRefreshStatus.Inactive刷新状态(Inactive、Drag、OverDrag、Refresh、Done)
offsetnumber0下拉偏移量
dragTextResourceStr'下拉刷新'下拉时显示的文本
overDragTextResourceStr'释放刷新'超过阈值时显示的文本
refreshTextResourceStr'刷新中...'刷新中显示的文本
doneTextResourceStr'刷新完成'刷新完成显示的文本
textColorResourceColor'#bbb'文本颜色
fontFont文本字体
loadingColorResourceColor | LinearGradientLinearGradientloading 颜色
loadingSizeSizeOptionsloading 大小

方法

方法参数返回值说明
getText()ResourceStr根据当前状态返回对应的文本

RefreshFooterData 刷新底部数据

上拉加载更多底部的状态数据:

属性类型默认值说明
isShowbooleantrue是否显示底部组件
stateRefreshFooterStateRefreshFooterState.None加载状态
noneTextResourceStr'上拉加载更多'默认状态显示的文本
loadingTextResourceStr'加载中...'加载中显示的文本
noMoreTextResourceStr'没有更多了'没有更多数据时显示的文本
textColorResourceColor'#bbb'文本颜色
fontFont文本字体
loadingColorResourceColor'#bbb'loading 颜色
loadingSizeSizeOptionsloading 大小

方法

方法参数返回值说明
getText()ResourceStr根据当前状态返回对应的文本

RefreshFooterState 枚举

加载更多的状态枚举:

数值说明
None0默认状态
Loading1正在加载中
NoMore2没有更多数据
NoMore2没有更多数据

RefreshGlobalConfig 全局配置

全局配置类,用于设置所有RefreshList组件的默认样式和行为:

静态属性

属性类型默认值说明
headerBuilderWrappedBuilder<[IRefreshHeaderData]>-全局自定义刷新头部构建器
footerBuilderWrappedBuilder<[IRefreshFooterData]>-全局自定义刷新底部构建器
loadingBuilderWrappedBuilder<[]>-全局自定义加载构建器
emptyBuilderWrappedBuilder<[]>-全局自定义空状态构建器
headerInactiveTextResourceStr'刷新'头部非活动状态文本
headerDragTextResourceStr'下拉刷新'头部下拉状态文本
headerOverDragTextResourceStr'释放刷新'头部超过阈值状态文本
headerRefreshTextResourceStr'刷新中...'头部刷新中状态文本
headerDoneTextResourceStr'刷新完成'头部刷新完成状态文本
footerNoneTextResourceStr'上拉加载更多'底部默认状态文本
footerLoadingTextResourceStr'加载中...'底部加载中状态文本
footerNoMoreTextResourceStr'没有更多了'底部没有更多数据状态文本
headerTextColorResourceColor'#bbb'头部文本颜色
footerTextColorResourceColor'#bbb'底部文本颜色
headerTextFontFont头部文本字体
footerTextFontFont底部文本字体
headerLoadingColorResourceColor | LinearGradientLinearGradient头部loading颜色
footerLoadingColorResourceColor'#bbb'底部loading颜色
headerLoadingSizeSizeOptions头部loading大小
footerLoadingSizeSizeOptions底部loading大小
refreshOffsetnumber-设置触发刷新的下拉偏移量
pullDownRationumber-设置下拉跟手系数,有效值为0-1之间的值

使用示例

typescript
import { RefreshGlobalConfig, IRefreshHeaderData, RefreshStatus } from '@cxy/refreshlist'

// 全局自定义刷新头部
@Builder
function globalHeaderBuilder(item: IRefreshHeaderData) {
  GlobalHeader({ data: item.data })
}

// 配置全局设置
function setupGlobalConfig() {
  RefreshGlobalConfig.headerBuilder = wrapBuilder(globalHeaderBuilder)
  RefreshGlobalConfig.headerDragText = '下拉刷新数据'
  RefreshGlobalConfig.headerOverDragText = '释放立即刷新'
  RefreshGlobalConfig.headerRefreshText = '正在刷新数据...'
  RefreshGlobalConfig.headerDoneText = '刷新成功'
  RefreshGlobalConfig.footerNoneText = '上拉加载更多'
  RefreshGlobalConfig.footerLoadingText = '数据加载中...'
  RefreshGlobalConfig.footerNoMoreText = '亲,没有更多了'
  RefreshGlobalConfig.headerTextColor = '#333'
  RefreshGlobalConfig.footerTextColor = '#666'
}

// 在应用启动时调用
setupGlobalConfig()

IRefreshHeaderData 接口

刷新头部数据接口:

属性类型说明
dataRefreshHeaderData刷新头部状态数据

IRefreshFooterData 接口

刷新底部数据接口:

属性类型说明
dataRefreshFooterData刷新底部状态数据

RefreshListDivider 分割线接口

自定义分割线样式的接口:

属性类型必需说明
strokeWidthLength分割线宽度
colorResourceColor分割线颜色
startMarginLength起始边距
endMarginLength结束边距

RefreshListAttrModifier 属性修饰器

用于自定义更多List属性的修饰器类:

typescript
export class RefreshListAttrModifier implements AttributeModifier<ListAttribute> {
  applyNormalAttribute(instance: ListAttribute): void {
    // 在这里可以自定义更多List属性
    // 例如:背景色、边框、阴影等
  }
}

// 使用示例
class CustomAttrModifier extends RefreshListAttrModifier {
  applyNormalAttribute(instance: ListAttribute): void {
    instance.backgroundColor('#f5f5f5')
    instance.borderRadius(10)
    instance.padding(10)
  }
}

常见问题

Q: 如何禁用下拉刷新?

typescript
// 方法1:不传onRefresh回调
RefreshList({
  // ... 其他属性
})

// 方法2:设置pullDownRatio为0
RefreshList({
  pullDownRatio: 0,
  // ... 其他属性
})

Q: 如何禁用上拉加载更多?

typescript
// 方法1:不传onLoadMore回调(推荐)
RefreshList({
  onRefresh: () => this.refresh(),
  // 不传onLoadMore即可禁用上拉加载
})

// 方法2:动态控制显示/隐藏
this.controller.hideLoadMore(true) // 隐藏加载更多
this.controller.setHasmore(false) // 设置没有更多数据

Q: 如何监听列表滚动事件?

typescript
RefreshList({
  onDidScroll: (scrollOffset: number, scrollState: ScrollState) => {
    console.log(`滚动偏移: ${scrollOffset}`)
    // 可以根据滚动位置实现悬浮按钮显示/隐藏等功能
  },
  onScrollIndex: (start: number, end: number) => {
    console.log(`当前可见范围: ${start} - ${end}`)
    // 可以用于埋点统计、预加载等
  },
  onReachEnd: () => {
    console.log('滚动到底部')
    // 可以用于触发加载更多数据
  }
})

作者

@仙银 鸿蒙开源作品,欢迎持续关注 🌟Star💖赞助

1、hpack - 鸿蒙 HarmonyOS 一键打包上传分发测试工具。

2、Open-in-DevEco-Studio - macOS 直接在 Finder 工具栏上,使用 DevEco-Studio 打开鸿蒙工程。

3、cxy-theme - DevEco-Studio 绿色护眼背景主题

4、harmony-udid-tool - 简单易用的 HarmonyOS 设备 UDID 获取工具,适用于非开发人员。

5、SandboxFinder - 鸿蒙沙箱文件浏览器,支持模拟器和真机

6、WebServer - 鸿蒙轻量级Web服务器框架,类 Express.js API 风格。

7、SelectableMenu - 适用于聊天对话框中的文本选择菜单

8、RefreshList - 功能完善的上拉下拉加载组件,支持各种自定义。