# easy_refresh_scrolls **Repository Path**: mxlj/easy_refresh_scrolls ## Basic Information - **Project Name**: easy_refresh_scrolls - **Description**: harmonyos 简单易用的下拉上拉刷新工具 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-03-05 - **Last Updated**: 2025-12-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 名称 EasyRefreshScroll上拉,下拉刷新工具。 # 装饰器版本 [v1 装饰器版本](https://gitee.com/mxlj/easy_refresh.git) [v2 装饰器版本](https://gitee.com/mxlj/easy_refresh_scrolls.git) ### 注: - 从1.0.6版本开始支持refreshingContent自定义头部刷新区域,如果设置了refreshNode.contentNode,那么customFreshHeader?: CustomBuilder会失效。 之前版本的方法会保留 # 已知问题 # 介绍 基于ArkUI封装的上拉下拉刷新组件,支持列表、网格、瀑布流、以及各种自定义组件的刷新。 对EasyRefresh库的升级,全面采用了V2状态管理,代码的全面重构,把更多的权限控制交给使用者,它只负责刷新。业务方面和显示样式方面根据由使用者自行控制。 属性和使用方面比EasyRefresh库的属性更少,更加方便好用。 希望构建一种对使用者来说使用快捷,方便,不要让使用者在使用过程中感到复杂,繁琐的操作。 备注:之所以没有在EasyRefresh库上面直接重构,因为EasyRefresh库现在很多项目在使用,无法直接在这个库上面进行修改,所以才有了EasyRefreshScroll这个库,再次感谢大家的支持和使用。 - 1、支持List列表、Gird、WaterFlow、自定义组件的Scroll上拉下拉刷新 - 2、支持自定义刷新header,footer刷新样式 - 3、支持自定义插入头部信息,以及底部信息 # 效果展示 动态效果:  静态效果: 注:请下载demo详情查看效果。 #### 更多案例 可以查看相关[Demo并下载](https://gitee.com/mxlj/easy_refresh_scrolls.git)。 运行Demo,如果自身相关开发环境不一致,会运行失败,可更改环境或者直接源码复制至您的项目即可。 # 开发环境 DevEco Studio 5.0.1 Release,Builder Version:5.0.5.310 Api版本:12 # 快速上手 ## 安装方式 ### 1、命令安装: 在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。 建议:可以自行指定安装目录 安装: ``` ohpm install @easy_refresh/easy_refresh_scroll ``` 版本更新: ``` ohpm update @easy_refresh/easy_refresh_scroll ``` ### 2、在工程的oh-package.json5中设置三方包依赖,配置示例如下: ``` "dependencies": { "@easy_refresh/easy_refresh_scroll": "^1.0.4"} ``` 下载之后,把har包复制项目中,目录自己创建,如下,我创建了一个libs目录,复制进去 引入之后,进行同步项目,点击Sync Now即可,当然了你也可以,将鼠标放置在报错处会出现提示,在提示框中点击Run 'ohpm install'。 ### 属性介绍 | 属性 | 类型 | 说明 | |----------------------|------------------|----------------------------------------------------| | finished | boolean | 是否还有下一页数据(必填) | | isEmpty | boolean | 是否没有数据(必填) | | pullUpTimer | number | 默认上拉加载显示停留时间,默认1000(非必填) | | isAutoRefresh | boolean | 是否开启主动刷新,默认false(非必填) | | finishText | string | 底部没有更多显示文字,默认我是有底线的~~~(非必填) | | loadingText | string | 底部加载中的示文字,默认正在加载中...(非必填) | | refreshOffset | number | 下来刷新触发的距离,默认64(非必填) | | pullDownRatio | number undefined | 有效值为0-1之间的值,小于0的值会被视为0,大于1的值会被视为1,默认undefined(非必填) | | disEnablePullDownRefresh | boolean | 禁用下拉刷新,默认关闭false(非必填) | | disEnablePullUpRefresh | boolean | 禁用上拉刷新,默认关闭false(非必填) | | isCustomRefresh | boolean | 是否开启自定义上拉刷新(非必填) | | customFreshHeader | @BuilderParam | 自定义的刷新头部信息(非必填) | | customFreshFooter | @BuilderParam | 自定义刷新尾部信息(非必填) | | customHeader | @BuilderParam | 自定义插入的头部信息(非必填) | | customFooter | @BuilderParam | 自定义插入的头部信息(非必填) | | isCustomNoMore | @BuilderParam | 是否开启自定义底部没有更多内容显示信息,默认false(非必填) | | customNoMoreView | @BuilderParam | 自定义底部没有更多内容显示信息(非必填)需要配合isCustomNoMore一起使用才会生效 | | contentView | @BuilderParam | 内容区域(必填) | | customEmptyView | @BuilderParam | 自定义空白页面(非必填) | | refreshCallBack | () => void | 下拉刷新的回调方法 | | loadMoreCallBack | () => void | 上拉加载更多的回调方法 | | controller | @Param | 控制器,默认可以不需要传入,但是监控滚动事件的时候需要传入 | | onDidScroll | @Event | 滚动事件的回调 | | onScrollStop | @Event | 滚动事件的回调 | | onScrollStart | @Event | 滚动事件的回调 | | onChangeState | @Event | 下拉刷新状态的回调 | # List的使用 #### 关于网络请求部分的模拟代码: ``` //网络请求方法: async getData(append: boolean) { setTimeout(() => { if (!append) { this.page = 1 } let array: number[] = []; let startIndex = (this.page - 1) * 10; let endIndex = this.page * 10; for (let index = startIndex; index < endIndex; index++) { array.push(index); } if(append){ this.dataArray.push(...array) }else { this.dataArray = [] this.dataArray = array } this.page ++ }, 500) } ``` #### 自定义没有更多内容 ``` @Builder noMoreView() { Row() { Text('我是list自定义的没有更多内容了') .fontColor(Color.White) } .justifyContent(FlexAlign.Center) .backgroundColor(Color.Brown) .width('100%') .height(60) } ``` #### 自定义空白页 ``` @Builder customEmptyView(){ Row(){ Text('我是list自定义的空白页') .fontSize(16) .fontColor(Color.Red) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } ``` #### List使用 ``` build() { NavDestination() { Column() { NavBarView({ title: this.params?.title }) EasyFreshScroll({ finished: this.dataArray.length < this.total ? true : false, //是否有下一页 isEmpty: this.dataArray.length > 0 ? false : true, //是否为空页面 isAutoRefresh:false, //是否开启进入页面的时候进行主动刷新 disEnablePullUpRefresh:false,//禁用上拉 isCustomNoMore:false, //开启自定义没有更多内容,默认false refreshCallBack: (async () => { await this.getData(false) //下拉网络请求的回调 }), loadMoreCallBack: (async () => { await this.getData(true) //上拉加载更多的回调 }), contentView: () => { this.listView() }, // 如果不自定义空白页,会使用默认的空白页面,如果既不想显示默认的空白, // 只想显示一个空白的内容,直接给自定义空白页,给一个空的就可以了, // 不指定任何内容 // customEmptyView:()=>{ // this.customEmptyView() // } customNoMoreView:()=>{ this.noMoreView() }, onDidScroll:(xOffset: number, yOffset: number, scrollState: ScrollState)=>{ }, }) .layoutWeight(1) } .width('100%') .layoutWeight(1) .margin({ top: ScreenManager.getInstance().model?.topHeight, bottom: ScreenManager.getInstance().model?.bottomHeight }) } .onReady((ctx) => { const item = ctx.pathInfo.param as TitleItemModel this.params = item }) .hideTitleBar(true) } ``` # Gird的使用 ``` build() { NavDestination(){ Column() { NavBarView({title:this.params?.title}) EasyFreshScroll({ finished: this.dataArray.length < this.total ? true : false, //是否有下一页 isEmpty: this.dataArray.length > 0 ? false : true, //是否为空页面 isAutoRefresh:false, //是否开启进入页面的时候进行主动刷新 refreshCallBack: (async () => { await this.getData(false) //下拉网络请求的回调 }), loadMoreCallBack: (async () => { await this.getData(true) //上拉加载更多的回调 }), contentView: () => { this.contentView() }, // 如果不自定义空白页,会使用默认的空白页面,如果既不想显示默认的空白, // 只想显示一个空白的内容,直接给自定义空白页,给一个空的就可以了, // 不指定任何内容 // customEmptyView:()=>{ // this.customEmptyView() // } }) .layoutWeight(1) } .width('100%') .layoutWeight(1) .padding({ top:ScreenManager.getInstance().model?.topHeight, bottom: ScreenManager.getInstance().model?.bottomHeight }) } .onReady((ctx)=>{ const item = ctx.pathInfo.param as TitleItemModel this.params = item }) .hideTitleBar(true) } ``` # WaterFlow的使用 ``` build() { NavDestination(){ Column() { NavBarView({title:this.params?.title}) EasyFreshScroll({ finished: this.dataArray.length < this.total ? true : false, //是否有下一页 isEmpty: this.dataArray.length > 0 ? false : true, //是否为空页面 isAutoRefresh:false, //是否开启进入页面的时候进行主动刷新 refreshCallBack: (async () => { await this.getData(false) //下拉网络请求的回调 }), loadMoreCallBack: (async () => { await this.getData(true) //上拉加载更多的回调 }), contentView: () => { this.contentView() }, // 如果不自定义空白页,会使用默认的空白页面,如果既不想显示默认的空白, // 只想显示一个空白的内容,直接给自定义空白页,给一个空的就可以了, // 不指定任何内容 // customEmptyView:()=>{ // this.customEmptyView() // } }) .layoutWeight(1) } .width('100%') .layoutWeight(1) .padding({ top:ScreenManager.getInstance().model?.topHeight, bottom: ScreenManager.getInstance().model?.bottomHeight }) } .onReady((ctx)=>{ const item = ctx.pathInfo.param as TitleItemModel this.params = item }) .hideTitleBar(true) } ``` # Scroll自定义的使用 ``` build() { NavDestination(){ Column() { NavBarView({title:this.params?.title}) EasyFreshScroll({ finished: false, //是否有下一页 isEmpty: this.dataArray.length > 0 ? false : true, //是否为空页面 isAutoRefresh:false, //是否开启进入页面的时候进行主动刷新 refreshCallBack: (async () => { await this.getData(false) //下拉网络请求的回调 }), loadMoreCallBack: (async () => { await this.getData(true) //上拉加载更多的回调 }), contentView: () => { this.contentItem() }, // 如果不自定义空白页,会使用默认的空白页面,如果既不想显示默认的空白, // 只想显示一个空白的内容,直接给自定义空白页,给一个空的就可以了, // 不指定任何内容 // customEmptyView:()=>{ // this.customEmptyView() // } }) .layoutWeight(1) } .width('100%') .layoutWeight(1) .padding({ top:ScreenManager.getInstance().model?.topHeight, bottom: ScreenManager.getInstance().model?.bottomHeight }) } .onReady((ctx)=>{ const item = ctx.pathInfo.param as TitleItemModel this.params = item }) .hideTitleBar(true) } ``` #### 更多案例 可以查看相关[Demo并下载](https://gitee.com/mxlj/easy_refresh_scroll.git)。 运行Demo,如果自身相关开发环境不一致,会运行失败,可更改环境或者直接源码复制至您的项目即可。 #### 联系作者 如果您在使用上有问题,解决不了,或者查看精华的鸿蒙技术文章,QQ邮箱:3316368400@qq.com。 #### 贡献者 非常感谢大家对本项目的付出,在此感谢大家的努力,欢迎更多的同学加入进来交流,名次不分先后。
#### License ``` Copyright (C) AbnerMing, HarmonyOsRefresh Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` [easy_refresh_scroller](..%2F..%2F..%2Fsshkey%2Feasy_refresh_scroller)