diff --git a/README.md b/README.md index 207b3ed3e6c98f50ddb7bb548ca7f40579abba40..dbcf667b37bc58a28f79a75adf606029c945b154 100644 --- a/README.md +++ b/README.md @@ -26,101 +26,53 @@ OpenHarmony ohpm ### 简单示例 -```typescript -import { ElfRefreshComponent } from '@duke/elf-refresh'; +```typescript +import { ElfRefreshComponent } from '@duke/elf-refresh'; import { TitleBar } from '../components/TitleBar'; -@ -Entry -@ -Component -struct -ListPage -{ - @ - State - data: string[] = [] - - aboutToAppear(): - void { - for - ( - let - i = 0 - ; - i - < - 100 - ; - i - ++ - ) - { - this - . - data - . - push - ( - 'item' - + - i - ) +@Entry +@Component +struct ListPage { + @State data: string[] = []; + aboutToAppear(): void { + for (let i = 0; i < 100; i++) { + this.data.push('item' + i); + } } -} - -@ -Builder -builderList() -{ - List() - { - ForEach(this.data, (item: string) => { - ListItem() - { - Text("测试数据" + item) + @Builder builderList() { + List() { + ForEach(this.data, (item: string) => { + ListItem() { Text("测试数据" + item) .width("95%") .height(50) .margin(10) .textAlign(TextAlign.Center) - .border({ width: 1, color: Color.Pink }) - } - }) - } - . - height('100%') + .border({ width: 1, color: Color.Pink }) + } + }) + } + .height('100%') .width('100%') -} - -build() -{ - Column() - { - TitleBar({ - title: '普通List', - }) - ElfRefreshComponent({ - content: () => { - this.builderList() - }, - onRefresh: async () => { - console.log('onRefresh') - return true - }, - onLoadMore: async () => { - console.log('onLoadMore') - return true - } - }).layoutWeight(1) + //下面代码建议添加,添加了会让刷新更流畅 + .edgeEffect(EdgeEffect.None) } - . - height('100%') - .width('100%') -} + build() { + Column() { + TitleBar({ title: '普通List', }) + ElfRefreshComponent({ + content: () => { this.builderList() }, + onRefresh: async () => { + console.log('onRefresh'); + return true; }, + onLoadMore: async () => { + console.log('onLoadMore'); + return true; } + }).layoutWeight(1) + }.height('100%') + .width('100%') + } } - ``` - ## 接口说明 ### ElfRefreshComponent @@ -136,6 +88,13 @@ build() | onRefresh | () => Promise | 返回值为true则刷新成功,false则刷新失败 | | onLoadMore | () => Promise | 返回值为true则加载成功,false则加载失败 | +### ElfGlobalConfig +| 方法名 | 入参 | 说明 | +|:----------------------:|:--------------------------------------------:|:-------------------------------:| +| initGlobalConfig | ElfCustomHeaderFooter,ElfRefreshConfigurator | 全局配置,配置全局刷新组件的默认配置,默认配置会覆盖组件的配置 | +| getDefaultCustom | | 获取全局Header和Footer组件 | +| getDefaultConfigurator | | 获取全局刷新组件的默认配置 | + ### ElfRefreshConfigurator | 属性 | 功能描述描述 | @@ -151,6 +110,7 @@ build() | refreshCompleteTextHoldTime | 下拉刷新完毕后, 刷新成功文本停留的时间 | | headerStyle | 头部样式 | | footerStyle | 底部样式 | +| copyWith | 拷贝配置并更新配置 | ## 自定义HeaderFooter @@ -192,7 +152,7 @@ DevEco Studio: 5.0.5.315, SDK: HarmonyOS 5.0.1 Release Ohos_sdk_public 5.0.1.115 ## 目录结构 ```` -|---- eventpost +|---- ElfRefresh | |---- AppScrope # 示例代码文件夹 | |---- entry # 示例代码文件夹 | |---- examples # 示例代码文件夹 diff --git a/entry/oh-package-lock.json5 b/entry/oh-package-lock.json5 index 00b2a2a0bfad928cd2e88104ebfbfdf7109a91fa..7124489777bcec6d1a313de8a87c3cd676310cd9 100644 --- a/entry/oh-package-lock.json5 +++ b/entry/oh-package-lock.json5 @@ -10,7 +10,7 @@ "packages": { "@duke/elf-refresh@../library": { "name": "@duke/elf-refresh", - "version": "1.0.0", + "version": "1.0.1", "resolved": "../library", "registryType": "local" } diff --git a/entry/src/main/ets/pages/ListPage.ets b/entry/src/main/ets/pages/ListPage.ets index 91d8eace4b786663a4b1b7bd4df25d7fad912897..65e625e3030cba82b9918a284879d9e86880b55a 100644 --- a/entry/src/main/ets/pages/ListPage.ets +++ b/entry/src/main/ets/pages/ListPage.ets @@ -1,4 +1,4 @@ -import { ElfRefreshComponent } from '@duke/elf-refresh'; +import { ElfGlobalConfig, ElfRefreshComponent } from '@duke/elf-refresh'; import { TitleBar } from '../components/TitleBar'; @Entry @@ -27,6 +27,8 @@ struct ListPage { }) }.height('100%') .width('100%') + //下面代码建议添加,添加了会让刷新更流畅 + .edgeEffect(EdgeEffect.None) } build() { @@ -35,6 +37,7 @@ struct ListPage { title: '普通List', }) ElfRefreshComponent({ + refreshConfigurator:ElfGlobalConfig.getInstance().getDefaultConfigurator(), content:()=>{this.builderList()}, onRefresh:async ()=>{ console.log('onRefresh') diff --git a/library/BuildProfile.ets b/library/BuildProfile.ets index 3a501e5ddee8ea6d28961648fc7dd314a5304bd4..e11789bc9ded2139f17563a59d2382b855e55ffb 100644 --- a/library/BuildProfile.ets +++ b/library/BuildProfile.ets @@ -1,9 +1,9 @@ /** * Use these variables when you tailor your ArkTS code. They must be of the const type. */ -export const HAR_VERSION = '1.0.0'; -export const BUILD_MODE_NAME = 'debug'; -export const DEBUG = true; +export const HAR_VERSION = '1.0.1'; +export const BUILD_MODE_NAME = 'release'; +export const DEBUG = false; export const TARGET_NAME = 'default'; /** diff --git a/library/CHANGELOG.md b/library/CHANGELOG.md index 81a9620a06905e2290d82eb1d3b86a6999cae15e..8d8ca0b8cd0817e4f49dd2d8bf89f2f359e5c974 100644 --- a/library/CHANGELOG.md +++ b/library/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [v1.0.1] 2025.03.14 + +- 优化基础Header和Footer的样式 +- 添加全局的默认配置 + ## [v1.0.0] 2025.03.12 - 第一版正式可用版本 \ No newline at end of file diff --git a/library/Index.ets b/library/Index.ets index b8d6f57b92910a8d609be55f02ec96b3e4e95c66..96ef542df037e8defcdcd3c7e109a0de97a32f6b 100644 --- a/library/Index.ets +++ b/library/Index.ets @@ -14,4 +14,6 @@ export { ElfRefreshHeader } from "./src/main/ets/model/ElfRefreshHeader"; export { ElfRefreshConfigurator } from "./src/main/ets/model/ElfRefreshConfigurator"; -export { ElfRefreshController } from "./src/main/ets/ElfRefreshController"; \ No newline at end of file +export { ElfRefreshController } from "./src/main/ets/ElfRefreshController"; + +export { ElfGlobalConfig } from "./src/main/ets/ElfGlobalConfig"; \ No newline at end of file diff --git a/library/README.md b/library/README.md index 207b3ed3e6c98f50ddb7bb548ca7f40579abba40..dbcf667b37bc58a28f79a75adf606029c945b154 100644 --- a/library/README.md +++ b/library/README.md @@ -26,101 +26,53 @@ OpenHarmony ohpm ### 简单示例 -```typescript -import { ElfRefreshComponent } from '@duke/elf-refresh'; +```typescript +import { ElfRefreshComponent } from '@duke/elf-refresh'; import { TitleBar } from '../components/TitleBar'; -@ -Entry -@ -Component -struct -ListPage -{ - @ - State - data: string[] = [] - - aboutToAppear(): - void { - for - ( - let - i = 0 - ; - i - < - 100 - ; - i - ++ - ) - { - this - . - data - . - push - ( - 'item' - + - i - ) +@Entry +@Component +struct ListPage { + @State data: string[] = []; + aboutToAppear(): void { + for (let i = 0; i < 100; i++) { + this.data.push('item' + i); + } } -} - -@ -Builder -builderList() -{ - List() - { - ForEach(this.data, (item: string) => { - ListItem() - { - Text("测试数据" + item) + @Builder builderList() { + List() { + ForEach(this.data, (item: string) => { + ListItem() { Text("测试数据" + item) .width("95%") .height(50) .margin(10) .textAlign(TextAlign.Center) - .border({ width: 1, color: Color.Pink }) - } - }) - } - . - height('100%') + .border({ width: 1, color: Color.Pink }) + } + }) + } + .height('100%') .width('100%') -} - -build() -{ - Column() - { - TitleBar({ - title: '普通List', - }) - ElfRefreshComponent({ - content: () => { - this.builderList() - }, - onRefresh: async () => { - console.log('onRefresh') - return true - }, - onLoadMore: async () => { - console.log('onLoadMore') - return true - } - }).layoutWeight(1) + //下面代码建议添加,添加了会让刷新更流畅 + .edgeEffect(EdgeEffect.None) } - . - height('100%') - .width('100%') -} + build() { + Column() { + TitleBar({ title: '普通List', }) + ElfRefreshComponent({ + content: () => { this.builderList() }, + onRefresh: async () => { + console.log('onRefresh'); + return true; }, + onLoadMore: async () => { + console.log('onLoadMore'); + return true; } + }).layoutWeight(1) + }.height('100%') + .width('100%') + } } - ``` - ## 接口说明 ### ElfRefreshComponent @@ -136,6 +88,13 @@ build() | onRefresh | () => Promise | 返回值为true则刷新成功,false则刷新失败 | | onLoadMore | () => Promise | 返回值为true则加载成功,false则加载失败 | +### ElfGlobalConfig +| 方法名 | 入参 | 说明 | +|:----------------------:|:--------------------------------------------:|:-------------------------------:| +| initGlobalConfig | ElfCustomHeaderFooter,ElfRefreshConfigurator | 全局配置,配置全局刷新组件的默认配置,默认配置会覆盖组件的配置 | +| getDefaultCustom | | 获取全局Header和Footer组件 | +| getDefaultConfigurator | | 获取全局刷新组件的默认配置 | + ### ElfRefreshConfigurator | 属性 | 功能描述描述 | @@ -151,6 +110,7 @@ build() | refreshCompleteTextHoldTime | 下拉刷新完毕后, 刷新成功文本停留的时间 | | headerStyle | 头部样式 | | footerStyle | 底部样式 | +| copyWith | 拷贝配置并更新配置 | ## 自定义HeaderFooter @@ -192,7 +152,7 @@ DevEco Studio: 5.0.5.315, SDK: HarmonyOS 5.0.1 Release Ohos_sdk_public 5.0.1.115 ## 目录结构 ```` -|---- eventpost +|---- ElfRefresh | |---- AppScrope # 示例代码文件夹 | |---- entry # 示例代码文件夹 | |---- examples # 示例代码文件夹 diff --git a/library/oh-package.json5 b/library/oh-package.json5 index 916c49f6d9063bc1eff783fa98f028a56d38d1fc..13d442149590fc552d13252791d011be7861d0d1 100644 --- a/library/oh-package.json5 +++ b/library/oh-package.json5 @@ -1,6 +1,6 @@ { "name": "@duke/elf-refresh", - "version": "1.0.0", + "version": "1.0.1", "description": "OpenHarmony 刷新组件,支持下拉刷新和上拉加载更多,支持各种组件,List、Grid,支持header,footer,目标打造HarmonyOS的SmartRefreshLayout", "main": "Index.ets", "author": "duke", diff --git a/library/src/main/ets/ElfGlobalConfig.ets b/library/src/main/ets/ElfGlobalConfig.ets new file mode 100644 index 0000000000000000000000000000000000000000..bdb0588609710bfe3e82e67b159d2bbc381e79c9 --- /dev/null +++ b/library/src/main/ets/ElfGlobalConfig.ets @@ -0,0 +1,34 @@ +import { ClassicsHeaderFooter } from "./components/ClassicsHeaderFooter" +import { ElfCustomHeaderFooter } from "./components/ElfCustomHeaderFooter" +import { ElfRefreshConfigurator } from "./model/ElfRefreshConfigurator" + +// 步骤1:创建全局配置管理器 +export class ElfGlobalConfig { + // 单例模式 + private static instance: ElfGlobalConfig = new ElfGlobalConfig() + static getInstance(): ElfGlobalConfig { + return ElfGlobalConfig.instance + } + + // 全局默认配置 + private defaultCustom: ElfCustomHeaderFooter = new ClassicsHeaderFooter() + private defaultConfigurator: ElfRefreshConfigurator = new ElfRefreshConfigurator() + + // 初始化全局配置(应用启动时调用) + initGlobalConfig(custom?: ElfCustomHeaderFooter, configurator?: ElfRefreshConfigurator) { + if (custom) { + this.defaultCustom = custom + } + if (configurator) { + this.defaultConfigurator = configurator + } + } + + getDefaultCustom(): ElfCustomHeaderFooter { + return this.defaultCustom + } + + getDefaultConfigurator(): ElfRefreshConfigurator { + return this.defaultConfigurator + } +} \ No newline at end of file diff --git a/library/src/main/ets/components/ClassicsHeaderFooter.ets b/library/src/main/ets/components/ClassicsHeaderFooter.ets index ffd235cee837638deb3120a4918f12b8bf9246b9..e6c0733ef68715ca6db76513f7af31b8ea101d42 100644 --- a/library/src/main/ets/components/ClassicsHeaderFooter.ets +++ b/library/src/main/ets/components/ClassicsHeaderFooter.ets @@ -10,7 +10,6 @@ struct ElfClassicsHeaderCell { @Param @Require header: ElfRefreshHeader @Local title: ResourceStr = $r('app.string.elf_header_pulling') @Local lastUpdateTime: string = '' - @Local refreshIng: boolean = false private updateTimeFormat = this.getUIContext().getHostContext()?.resourceManager.getStringSync($r('app.string.elf_header_update')) @@ -26,7 +25,6 @@ struct ElfClassicsHeaderCell { } this.header.onStart = () => { this.title = $r('app.string.elf_header_pulling') - this.refreshIng = false } this.header.onMoving = () => { @@ -39,7 +37,6 @@ struct ElfClassicsHeaderCell { this.header.onReleased = () => { this.title = $r('app.string.elf_header_refreshing') - this.refreshIng = true } } @@ -50,9 +47,32 @@ struct ElfClassicsHeaderCell { build() { Row({ space: 8 }) { Stack() { - LoadingProgress() - .width(20) - .height(20) + if (this.header.state == RefreshState.IS_PULL_DOWN_1 || this.header.state == RefreshState.IS_PULL_DOWN_2) { + Image($r('sys.media.ohos_ic_public_arrow_down')) + .rotate({ + x: 0, + y: 0, + z: 1, + centerX: '50%', + centerY: '50%', + angle: this.header.state == RefreshState.IS_PULL_DOWN_2 ? 180 : 0 + }) + .animation({ + duration: 300, + curve: Curve.EaseIn, + iterations: 1, + playMode: PlayMode.Normal, + }) + .fillColor('#666666') + .width(20) + .height(20) + .transition(TransitionEffect.OPACITY) + } else { + LoadingProgress() + .width(20) + .height(20) + .transition(TransitionEffect.OPACITY) + } } Column() { @@ -64,6 +84,7 @@ struct ElfClassicsHeaderCell { Text(this.lastUpdateTime) .fontColor('#7c7c7c') .fontSize(12) + .transition(TransitionEffect.OPACITY) } } .align(Alignment.Center) @@ -108,9 +129,32 @@ struct ElfClassicsFooterCell { if (this.footer.hasMore) { Stack() { - LoadingProgress() - .width(20) - .height(20) + if(this.footer.state == RefreshState.IS_PULL_UP_1 || this.footer.state == RefreshState.IS_PULL_UP_2) { + Image($r('sys.media.ohos_ic_public_arrow_down')) + .rotate({ + x: 0, + y: 0, + z: 1, + centerX: '50%', + centerY: '50%', + angle: this.footer.state ==RefreshState.IS_PULL_UP_1 ? 180 : 0 + }) + .animation({ + duration: 300, + curve: Curve.EaseIn, + iterations: 1, + playMode: PlayMode.Normal, + }) + .fillColor('#666666') + .width(20) + .height(20) + .transition(TransitionEffect.OPACITY) + }else { + LoadingProgress() + .width(20) + .height(20) + .transition(TransitionEffect.OPACITY) + } } } diff --git a/library/src/main/ets/components/ElfRefreshComponent.ets b/library/src/main/ets/components/ElfRefreshComponent.ets index 5545614eac42da0310c696a13e04de1e79cb7dc2..aa73f48e0e0532471d2c04f19c8791b07d84dd94 100644 --- a/library/src/main/ets/components/ElfRefreshComponent.ets +++ b/library/src/main/ets/components/ElfRefreshComponent.ets @@ -2,18 +2,18 @@ import { util } from "@kit.ArkTS" import { ElfCustomHeaderFooter } from "./ElfCustomHeaderFooter"; import { ElfRefreshConfigurator } from "../model/ElfRefreshConfigurator"; import { RefreshState } from "../constant/RefreshState"; -import { ClassicsHeaderFooter } from "./ClassicsHeaderFooter"; import { ElfRefreshHeader } from "../model/ElfRefreshHeader"; import { ElfLoadFooter } from "../model/ElfLoadFooter"; import { AnimatorResult } from "@kit.ArkUI"; import { CustomStyle } from "../constant/CustomStyle"; import { ElfRefreshController } from "../ElfRefreshController"; +import { ElfGlobalConfig } from "../../../../Index"; @ComponentV2 export struct ElfRefreshComponent { @BuilderParam content: () => void - @Param @Once custom: ElfCustomHeaderFooter = new ClassicsHeaderFooter() - @Param @Once refreshConfigurator: ElfRefreshConfigurator = new ElfRefreshConfigurator() + @Param @Once custom: ElfCustomHeaderFooter = ElfGlobalConfig.getInstance().getDefaultCustom() + @Param @Once refreshConfigurator: ElfRefreshConfigurator = ElfGlobalConfig.getInstance().getDefaultConfigurator() @Param @Once controller: ElfRefreshController = new ElfRefreshController() @Param childOffsetInput: number = 0 @Param targetRefreshId: string | undefined = undefined @@ -135,9 +135,13 @@ export struct ElfRefreshComponent { y: this.trYTop || this.trYBottom }) - if (this.refreshConfigurator.getHasRefresh() && this.custom.builderHeader) { + if (this.refreshConfigurator.getHasRefresh() && (this.custom.builderHeader || ElfGlobalConfig.getInstance().getDefaultCustom().builderHeader)) { Stack({ alignContent: Alignment.Bottom }) { - this.custom.builderHeader.builder(this.header) + if(this.custom.builderHeader) { + this.custom.builderHeader.builder(this.header) + }else { + ElfGlobalConfig.getInstance().getDefaultCustom().builderHeader?.builder(this.header) + } }.zIndex(this.refreshConfigurator.getHeaderStyle() == CustomStyle.FixedBehind ? 1 : 3) .height(this.refreshConfigurator.getHeaderStyle() == CustomStyle.Scale ? this.trYTop : this.refreshConfigurator.getRefreshHeight()) @@ -147,9 +151,13 @@ export struct ElfRefreshComponent { this.trYTop - this.refreshConfigurator.getRefreshHeight() : 0 }) } - if (this.refreshConfigurator.getHasLoadMore() && this.custom.builderFooter) { + if (this.refreshConfigurator.getHasLoadMore() && (this.custom.builderFooter || ElfGlobalConfig.getInstance().getDefaultCustom().builderFooter)) { Stack({ alignContent: Alignment.Top }) { - this.custom.builderFooter.builder(this.footer) + if(this.custom.builderFooter) { + this.custom.builderFooter.builder(this.footer) + }else { + ElfGlobalConfig.getInstance().getDefaultCustom().builderFooter?.builder(this.footer) + } }.zIndex(this.refreshConfigurator.getFooterStyle() == CustomStyle.FixedBehind ? 1 : 3) .height(this.refreshConfigurator.getFooterStyle() == CustomStyle.Scale ? this.trYBottom : this.refreshConfigurator.getRefreshHeight()) @@ -264,6 +272,12 @@ export struct ElfRefreshComponent { (!this.targetRefreshId || this.targetRefreshId == target.getId())) { // 找到将要组成并行手势的识别器 // 保存当前组件的识别器 this.childRecognizer = others[i]; // 保存将要组成并行手势的识别器 + let target = this.childRecognizer.getEventTargetInfo() as ScrollableTargetInfo; + if (target instanceof ScrollableTargetInfo) { + if (target.isEnd()||target.isBegin()) { + this.childRecognizer.setEnabled(false) + } + } return others[i]; // 返回将要组成并行手势的识别器 } } diff --git a/library/src/main/ets/constant/CustomStyle.ets b/library/src/main/ets/constant/CustomStyle.ts similarity index 100% rename from library/src/main/ets/constant/CustomStyle.ets rename to library/src/main/ets/constant/CustomStyle.ts diff --git a/library/src/main/ets/model/ElfRefreshConfigurator.ets b/library/src/main/ets/model/ElfRefreshConfigurator.ts similarity index 86% rename from library/src/main/ets/model/ElfRefreshConfigurator.ets rename to library/src/main/ets/model/ElfRefreshConfigurator.ts index acd7ac3c0700969cd4a22f7becbef4bcf03b4d41..cee03e898824905b809e6b3d89a6dfebc1bc6b5e 100644 --- a/library/src/main/ets/model/ElfRefreshConfigurator.ets +++ b/library/src/main/ets/model/ElfRefreshConfigurator.ts @@ -113,4 +113,18 @@ export class ElfRefreshConfigurator { getRefreshAnimDuration() { return this.refreshAnimDuration; } + + /** + * 创建新配置对象,合并当前配置与传入参数 + * @param params 需要覆盖的配置项(部分属性) + * @returns 新配置实例 + */ + copyWith(params: Partial): ElfRefreshConfigurator { + const newConfig = new ElfRefreshConfigurator() + // 复制当前对象属性 + Object.assign(newConfig, this) + // 覆盖指定属性 + Object.assign(newConfig, params) + return newConfig + } } \ No newline at end of file