前言
老早之前开源了一个刷新组件,提供了很多常见的功能,也封装了List,Grid,WaterFlow,虽然功能多,但也冗余比较多,随着时间的前去,暴露的问题就慢慢增多,虽然我也提供了通用的RefrshLayout,奈何很多人仍然有许多问题,但大部分都是相关属性以及用法的问题,对于我来说也比较苦恼,既然如此,那就只封装一个刷新加载,其它的自己实现好了,于是针对refresh的轻盈组件就剥离出来了。
因为它只是一个刷新组件,也仅仅是提供刷新能力,并不提供数据加载服务,这是和refrsh组件的不同之处,当然了,也是灵活之处,毕竟列表的组件是自己写的,需要什么样式更加灵活,但是在代码层次上也稍显冗余,不过有舍就有得。
目前已上传至了中心仓库,地址是:
https://ohpm.openharmony.cn/#/cn/detail/@abner%2Flithe_refresh
刷新库功能效果一览
1、所有功能
2、各个功能效果
快速使用
方式一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。
建议:在使用的模块路径下进行执行命令。
ohpm install @abner/lithe_refresh
方式二:在工程的oh-package.json5中设置三方包依赖,配置示例如下:
"dependencies": { "@abner/lithe_refresh": "^1.0.0"}
使用注意
可以使用LitheRefresh组件,包裹想刷新的任意组件,相对比较灵活,如果您想实现懒加载数据模式,建议结合提供的RefreshDataSource,可以让您实现更加方便。
有一点需要知道,如果是包裹的是可滑动组件,比如List,Grid,WaterFlow等,需要配合nestedScroll属性,来解决滑动之间的冲突。
代码案例
1、简单使用
controller: RefreshController = new RefreshController()//任意组件,可以是List、Grid,WaterFlow ……
@BuilderitemLayout() {Column() {}.width("100%").height("100%").backgroundColor(Color.Pink).justifyContent(FlexAlign.Center)}LitheRefresh({itemLayout: this.itemLayout,controller: this.controller,onRefresh: () => {//下拉刷新this.controller.finishRefresh()},onLoadMore: () => {//加载更多this.controller.finishLoadMore()}
})
2、List使用
@Entry
@Component
struct ListUpAndDownPage {@State testArray: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]scroller: Scroller = new Scroller()controller: RefreshController = new RefreshController()@BuilderitemLayout(_this: ListUpAndDownPage) {List({ scroller: _this.scroller, space: 20 }) {ForEach(_this.testArray, (item: number) => {ListItem() {Text('' + item).width('100%').height(80).fontSize(16).textAlign(TextAlign.Center).backgroundColor(0xFFFFFF).border({ width: 2, color: Color.Pink })}}, (item: string, index: number) => JSON.stringify(item) + "_" + index)}.scrollBar(BarState.Off).edgeEffect(EdgeEffect.None).width("100%").height("100%").padding({ left: 20, right: 20 }).nestedScroll({scrollForward: NestedScrollMode.PARENT_FIRST,scrollBackward: NestedScrollMode.PARENT_FIRST})}build() {Column() {LitheRefresh({scroller: this.scroller,controller: this.controller,itemLayout: () => {this.itemLayout(this)},onRefresh: () => {//下拉刷新setTimeout(() => {this.controller.finishRefresh()}, 2000)},onLoadMore: () => {//上拉加载setTimeout(() => {this.testArray.push(13)this.testArray.push(14)this.controller.finishLoadMore()}, 2000)}})}}
}
3、Grid使用
@Entry
@Component
struct GridUpAndDownPage {@State testArray: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]scroller: Scroller = new Scroller()controller: RefreshController = new RefreshController()@BuilderitemLayout(_this: GridUpAndDownPage) {Grid(_this.scroller) {ForEach(_this.testArray, (item: number) => {GridItem() {Text('' + item).width('100%').height(80).fontSize(16).textAlign(TextAlign.Center).backgroundColor(0xFFFFFF).border({ width: 2, color: Color.Pink })}}, (item: string, index: number) => JSON.stringify(item) + "_" + index)}.columnsTemplate("1fr 1fr").columnsGap(10).rowsGap(10).scrollBar(BarState.Off).edgeEffect(EdgeEffect.None).width("100%").height("100%").padding({ left: 20, right: 20 }).nestedScroll({scrollForward: NestedScrollMode.PARENT_FIRST,scrollBackward: NestedScrollMode.PARENT_FIRST})}build() {Column() {ActionBar({title: "Grid组件刷新",barBackgroundColor: Color.Red,leftText: "返回",onLeftClick: () => {router.back()},})LitheRefresh({scroller: this.scroller,controller: this.controller,itemLayout: () => {this.itemLayout(this)},onRefresh: () => {//下拉刷新setTimeout(() => {this.controller.finishRefresh()}, 2000)},onLoadMore: () => {//上拉加载setTimeout(() => {this.testArray.push(13)this.testArray.push(14)this.controller.finishLoadMore()}, 2000)}})}}
}
3、WaterFlow使用
这里没有使用提供RefreshDataSource,所以懒加载方式比较冗余,为了简洁代码,建议使用我提供的RefreshDataSource,可以让您的效率极大提升。
具体RefreshDataSource使用方式,可以查看Demo中LazyDataOperationPage页面。
@Entry@Componentstruct WaterFlowUpAndDownPage {scroller: Scroller = new Scroller()controller: RefreshController = new RefreshController()@BuilderitemLayout(_this: WaterFlowUpAndDownPage) {WaterFlowView({scroller: _this.scroller})}build() {Column() {LitheRefresh({scroller: this.scroller,controller: this.controller,itemLayout: () => {this.itemLayout(this)},onRefresh: () => {//下拉刷新setTimeout(() => {this.controller.finishRefresh()}, 2000)},onLoadMore: () => {//上拉加载setTimeout(() => {this.controller.finishLoadMore()}, 2000)}})}}}@Componentstruct WaterFlowView {@State minSize: number = 80@State maxSize: number = 180@State fontSize: number = 24@State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]scroller: Scroller = new Scroller()dataSource: WaterFlowDataSource = new WaterFlowDataSource()private itemWidthArray: number[] = []private itemHeightArray: number[] = []// 计算FlowItem宽/高getSize() {let ret = Math.floor(Math.random() * this.maxSize)return (ret > this.minSize ? ret : this.minSize)}// 设置FlowItem的宽/高数组setItemSizeArray() {for (let i = 0; i < 30; i++) {this.itemWidthArray.push(this.getSize())this.itemHeightArray.push(this.getSize())}}aboutToAppear() {this.setItemSizeArray()}build() {WaterFlow({ scroller: this.scroller }) {LazyForEach(this.dataSource, (item: number) => {FlowItem() {Column() {Text("N" + item).fontSize(12).height('16')}}.width('100%').height(this.itemHeightArray[item % 30]).backgroundColor(this.colors[item % 5])}, (item: string) => item)}.columnsTemplate("1fr 1fr").columnsGap(10).rowsGap(5).backgroundColor(0xFAEEE0).width('100%').height('100%').nestedScroll({scrollForward: NestedScrollMode.PARENT_FIRST,scrollBackward: NestedScrollMode.PARENT_FIRST})}}// 实现IDataSource接口的对象,用于瀑布流组件加载数据
export class WaterFlowDataSource implements IDataSource {private dataArray: number[] = []private listeners: DataChangeListener[] = []constructor() {for (let i = 0; i < 30; i++) {this.dataArray.push(i)}}// 获取索引对应的数据public getData(index: number): number {return this.dataArray[index]}// 通知控制器数据重新加载notifyDataReload(): void {this.listeners.forEach(listener => {listener.onDataReloaded()})}// 通知控制器数据增加notifyDataAdd(index: number): void {this.listeners.forEach(listener => {listener.onDataAdd(index)})}// 通知控制器数据变化notifyDataChange(index: number): void {this.listeners.forEach(listener => {listener.onDataChange(index)})}// 通知控制器数据删除notifyDataDelete(index: number): void {this.listeners.forEach(listener => {listener.onDataDelete(index)})}// 通知控制器数据位置变化notifyDataMove(from: number, to: number): void {this.listeners.forEach(listener => {listener.onDataMove(from, to)})}//通知控制器数据批量修改notifyDatasetChange(operations: DataOperation[]): void {this.listeners.forEach(listener => {listener.onDatasetChange(operations);})}// 获取数据总数public totalCount(): number {return this.dataArray.length}// 注册改变数据的控制器registerDataChangeListener(listener: DataChangeListener): void {if (this.listeners.indexOf(listener) < 0) {this.listeners.push(listener)}}// 注销改变数据的控制器unregisterDataChangeListener(listener: DataChangeListener): void {const pos = this.listeners.indexOf(listener)if (pos >= 0) {this.listeners.splice(pos, 1)}}// 增加数据public add1stItem(): void {this.dataArray.splice(0, 0, this.dataArray.length)this.notifyDataAdd(0)}// 在数据尾部增加一个元素public addLastItem(): void {this.dataArray.splice(this.dataArray.length, 0, this.dataArray.length)this.notifyDataAdd(this.dataArray.length - 1)}// 在指定索引位置增加一个元素public addItem(index: number): void {this.dataArray.splice(index, 0, this.dataArray.length)this.notifyDataAdd(index)}// 删除第一个元素public delete1stItem(): void {this.dataArray.splice(0, 1)this.notifyDataDelete(0)}// 删除第二个元素public delete2ndItem(): void {this.dataArray.splice(1, 1)this.notifyDataDelete(1)}// 删除最后一个元素public deleteLastItem(): void {this.dataArray.splice(-1, 1)this.notifyDataDelete(this.dataArray.length)}// 在指定索引位置删除一个元素public deleteItem(index: number): void {this.dataArray.splice(index, 1)this.notifyDataDelete(index)}// 重新加载数据public reload(): void {this.dataArray.splice(1, 1)this.dataArray.splice(3, 2)this.notifyDataReload()}
}
使用总结
在和可滑动组件使用的时候,记得一定要和nestedScroll属性配合使用,用于解决滑动冲突,除此之外,还需要传递滑动组件的scroller属性,用于手势操作。