diff --git a/README.md b/README.md index da12236298069fe5b9e1056f3ca078a1238aa12f..20a09fe27b279b83b080aef583df72ae49382ad2 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ struct ListPage { | refreshConfigurator | ElfRefreshConfigurator | 组件配置 | | controller | ElfRefreshController | 自动刷新控制和无更多数据控制 | | childOffsetInput | number | 对于非滑动组件又有滑动手势的组件提供解决滑动冲突的方案(如Web组件) 大于0则刷新不响应 注意该属性仅对刷新生效 | +| isSmartFind | boolean | 智能寻找刷新控件 默认开启,负责嵌套建议关闭,手动指定刷新组件 | +| interceptNestScroll | boolean | 拦截嵌套滑动刷新 默认关闭 | | targetRefreshId | string | 内容区存在嵌套滑动的情况,提供主内容id,解决滑动冲突的情况 | | onRefresh | () => Promise | 返回值为true则刷新成功,false则刷新失败 | | onLoadMore | () => Promise | 返回值为true则加载成功,false则加载失败 | diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 85411a7e19bf2718a031388ea60997ea7a945c9d..4165d3b48c1bb8f7d3f78417e33295ad9333ee55 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -11,6 +11,10 @@ struct Index { .onClick(() => { router.pushUrl({ url: 'pages/ListPage' }) }) + Button("一般页面刷新") + .onClick(() => { + router.pushUrl({ url: 'pages/NomPage' }) + }) Button("Web刷新") .onClick(() => { router.pushUrl({ url: 'pages/TestWebPage' }) @@ -25,6 +29,11 @@ struct Index { router.pushUrl({ url: 'pages/NestScollPage2' }) }) + Button("横向轮播") + .onClick(() => { + router.pushUrl({ url: 'pages/SwiperPage' }) + }) + Button("2楼效果展示") .onClick(() => { router.pushUrl({ url: 'pages/TwoPage' }) diff --git a/entry/src/main/ets/pages/NestScollPage1.ets b/entry/src/main/ets/pages/NestScollPage1.ets index 2ff166248f843b398ddf5019376dd58543b9c985..b16a6ac23299a40531f2f70f7bc6840318c9c444 100644 --- a/entry/src/main/ets/pages/NestScollPage1.ets +++ b/entry/src/main/ets/pages/NestScollPage1.ets @@ -33,6 +33,7 @@ struct NestScollPage { .width('100%') .backgroundColor(Color.Blue) }.height(100) + .id('test') } }.height('100%') .width('100%') diff --git a/entry/src/main/ets/pages/NestScollPage2.ets b/entry/src/main/ets/pages/NestScollPage2.ets index 7e6d59317670194510ff84026fef00501182da17..d82ee1aed15462a769c6283275558e69e2d80bf6 100644 --- a/entry/src/main/ets/pages/NestScollPage2.ets +++ b/entry/src/main/ets/pages/NestScollPage2.ets @@ -37,6 +37,7 @@ struct NestScollPage { scrollForward:NestedScrollMode.SELF_FIRST, scrollBackward:NestedScrollMode.SELF_FIRST, }) + .id('test') } }.height('100%') .width('100%') diff --git a/entry/src/main/ets/pages/NomPage.ets b/entry/src/main/ets/pages/NomPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..1dbac56420b0b43b2dd17cf0227d46418564cf06 --- /dev/null +++ b/entry/src/main/ets/pages/NomPage.ets @@ -0,0 +1,52 @@ +import { ElfGlobalConfig, ElfRefreshComponent } from '@duke/elf-refresh' +import { TitleBar } from '../components/TitleBar' + +@Entry +@Component +struct NomPage { + @State data: string[] = [] + + aboutToAppear(): void { + for (let i = 0; i < 10; i++) { + this.data.push('item' + i) + } + } + + @Builder + builderList(){ + Column() { + ForEach(this.data, (item: string) => { + Text("测试数据" + item) + .width("95%") + .height(50) + .margin(10) + .textAlign(TextAlign.Center) + .border({ width: 1, color: Color.Pink }) + }) + }.height('100%') + .width('100%') + //下面代码建议添加,添加了会让刷新更流畅 + } + + build() { + Column() { + TitleBar({ + title: '一般页面', + }) + ElfRefreshComponent({ + refreshConfigurator:ElfGlobalConfig.getInstance().getDefaultConfigurator(), + content:()=>{this.builderList()}, + onRefresh:async ()=>{ + console.log('onRefresh') + return true + }, + onLoadMore:async ()=>{ + console.log('onLoadMore') + return true + } + }).layoutWeight(1) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/entry/src/main/ets/pages/SwiperPage.ets b/entry/src/main/ets/pages/SwiperPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..f64edaf2d711958b5d79017bc6c2ac601e9f14fc --- /dev/null +++ b/entry/src/main/ets/pages/SwiperPage.ets @@ -0,0 +1,55 @@ +import { ElfGlobalConfig, ElfRefreshComponent } from '@duke/elf-refresh' +import { TitleBar } from '../components/TitleBar' + +@Entry +@Component +struct SwperPage { + @State data: string[] = [] + + aboutToAppear(): void { + for (let i = 0; i < 100; i++) { + this.data.push('item' + i) + } + } + + @Builder + builderList(){ + Swiper() { + 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%') + .width('100%') + } + + build() { + Column() { + TitleBar({ + title: 'Swiper', + }) + ElfRefreshComponent({ + refreshConfigurator:ElfGlobalConfig.getInstance().getDefaultConfigurator(), + content:()=>{this.builderList()}, + targetRefreshId:'1', + isSmart:false, + onRefresh:async ()=>{ + console.log('onRefresh') + return true + }, + onLoadMore:async ()=>{ + console.log('onLoadMore') + return true + } + }).layoutWeight(1) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/entry/src/main/ets/pages/TestWebPage.ets b/entry/src/main/ets/pages/TestWebPage.ets index fdb722f350059179fe2d3096d7d4c29a3b2779d4..8703b2b795c22e7a78ed151abc91058bedd5e0f7 100644 --- a/entry/src/main/ets/pages/TestWebPage.ets +++ b/entry/src/main/ets/pages/TestWebPage.ets @@ -34,6 +34,7 @@ struct TestWebPage { content:()=>{this.builderWeb()}, refreshConfigurator:this.refreshConfigurator, childOffsetInput:this.webScrollOffset, + targetRefreshId:'web', onRefresh:async ()=>{ this.webviewController.refresh() return true diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json index 06465e8f626321e192c35c42a4dc19ed009137c7..023ec6254b7ee8809f9efacc7e50c65559c4db63 100644 --- a/entry/src/main/resources/base/profile/main_pages.json +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -5,6 +5,8 @@ "pages/TestWebPage", "pages/NestScollPage2", "pages/NestScollPage1", - "pages/TwoPage" + "pages/TwoPage", + "pages/NomPage", + "pages/SwiperPage" ] } \ No newline at end of file diff --git a/library/BuildProfile.ets b/library/BuildProfile.ets index cab3453ea1340de0017578b1c0a42b8526d7c1a0..eb17d5049685669f3e4d9dc7c906a1bf2cde0774 100644 --- a/library/BuildProfile.ets +++ b/library/BuildProfile.ets @@ -2,8 +2,8 @@ * Use these variables when you tailor your ArkTS code. They must be of the const type. */ export const HAR_VERSION = '1.1.0'; -export const BUILD_MODE_NAME = 'release'; -export const DEBUG = false; +export const BUILD_MODE_NAME = 'debug'; +export const DEBUG = true; export const TARGET_NAME = 'default'; /** diff --git a/library/CHANGELOG.md b/library/CHANGELOG.md index ee529524a4672ef6dbdab402ad242bd530ddff9e..bb38c49dfb6482fcd652220b78374745c790e66d 100644 --- a/library/CHANGELOG.md +++ b/library/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [v1.1.1] 2025.03.21 + +- 新增智能搜索刷新组件 提升响应速度默认开启 可以应对80%的场景 +- 新增嵌套滑动拦截,减少不必要的滑动冲突 默认关闭 开启后,嵌套滑动不会触发组件能力 +- 修复无滑动组件无法上拉加载的情况 + ## [v1.1.0] 2025.03.18 - 修复潜在的bug, diff --git a/library/README.md b/library/README.md index da12236298069fe5b9e1056f3ca078a1238aa12f..20a09fe27b279b83b080aef583df72ae49382ad2 100644 --- a/library/README.md +++ b/library/README.md @@ -88,6 +88,8 @@ struct ListPage { | refreshConfigurator | ElfRefreshConfigurator | 组件配置 | | controller | ElfRefreshController | 自动刷新控制和无更多数据控制 | | childOffsetInput | number | 对于非滑动组件又有滑动手势的组件提供解决滑动冲突的方案(如Web组件) 大于0则刷新不响应 注意该属性仅对刷新生效 | +| isSmartFind | boolean | 智能寻找刷新控件 默认开启,负责嵌套建议关闭,手动指定刷新组件 | +| interceptNestScroll | boolean | 拦截嵌套滑动刷新 默认关闭 | | targetRefreshId | string | 内容区存在嵌套滑动的情况,提供主内容id,解决滑动冲突的情况 | | onRefresh | () => Promise | 返回值为true则刷新成功,false则刷新失败 | | onLoadMore | () => Promise | 返回值为true则加载成功,false则加载失败 | diff --git a/library/oh-package.json5 b/library/oh-package.json5 index d686cdf0a2c108f3aa62d5e51199269c0903b8c5..9aa01b5c634c630cbfa4058aa8431a996e6f171d 100644 --- a/library/oh-package.json5 +++ b/library/oh-package.json5 @@ -1,6 +1,6 @@ { "name": "@duke/elf-refresh", - "version": "1.1.0", + "version": "1.1.1", "description": "OpenHarmony 刷新组件,支持下拉刷新和上拉加载更多,支持各种组件,List、Grid,支持header,footer,目标打造HarmonyOS的SmartRefreshLayout", "main": "Index.ets", "author": "duke", diff --git a/library/src/main/ets/components/ElfRefreshComponent.ets b/library/src/main/ets/components/ElfRefreshComponent.ets index f32d8d3deec1f2755cedc38ae115ef28b362e985..f3beb8bccb16826b4432f02266643190986c7d9c 100644 --- a/library/src/main/ets/components/ElfRefreshComponent.ets +++ b/library/src/main/ets/components/ElfRefreshComponent.ets @@ -40,6 +40,17 @@ export struct ElfRefreshComponent { * 可以一定程度上当做开关使用 */ @Param childOffsetInput: number = 0 + /** + * 智能组件查找 + * 并且能够提升响应速度 + */ + @Param isSmartFind: boolean = true + + /** + * 是否拦截嵌套滚动事件 + * 默认不拦截 + */ + @Param interceptNestScroll: boolean = false /** * 对于存在嵌套滑动的情况,让框架能够准确的识别需要拦截的子组件id * 其余的不处理 @@ -62,11 +73,11 @@ export struct ElfRefreshComponent { return true } private currentId: string = util.generateRandomUUID() - private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Up | PanDirection.Down }) + private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Vertical }) private touchYOld: number = 0 private touchYNew: number = 0 - private childRecognizer: GestureRecognizer = new GestureRecognizer() - private currentRecognizer: GestureRecognizer = new GestureRecognizer() + private childRecognizer?: GestureRecognizer + private currentRecognizer?: GestureRecognizer private header = new ElfRefreshHeader(this.state, this.refreshConfigurator.getMaxTranslate(), this.refreshConfigurator.getRefreshHeight(), 0, 0) private twoHeader = new ElfRefreshHeader(this.state, this.refreshConfigurator.getMaxTranslate(), @@ -77,6 +88,7 @@ export struct ElfRefreshComponent { private animList: Set = new Set() private lastOffset: number = 0 private groupHeight: number = 0 + private isNest: boolean = false @Monitor('state') changeState(iMonitor: IMonitor) { @@ -244,29 +256,53 @@ export struct ElfRefreshComponent { height: '100%' }) .shouldBuiltInRecognizerParallelWith((_: GestureRecognizer, others: Array) => { - for (let i = 0; i < others.length; i++) { - let target = others[i].getEventTargetInfo(); - if (target) { - if (others[i].isBuiltIn() && - others[i].getType() == GestureControl.GestureType.PAN_GESTURE && - (!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) + if (this.isSmartFind) { + if (this.childRecognizer == undefined) { + this.childRecognizer = others[others.length - 1] + } + } + if(this.interceptNestScroll){ + this.isNest = others.length > 1 + } + if (this.childRecognizer == undefined) { + for (let i = 0; i < others.length; i++) { + let target = others[i].getEventTargetInfo(); + if (target) { + if (others[i].isBuiltIn() && + others[i].getType() == GestureControl.GestureType.PAN_GESTURE && + (!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]; // 返回将要组成并行手势的识别器 } - return others[i]; // 返回将要组成并行手势的识别器 } } + } else { + let target = this.childRecognizer.getEventTargetInfo() as ScrollableTargetInfo; + if (target instanceof ScrollableTargetInfo) { + if (target.isEnd() || target.isBegin()) { + this.childRecognizer.setEnabled(false) + } + } + return this.childRecognizer // 返回将要组成并行手势的识别器 } return undefined; }) .onGestureRecognizerJudgeBegin((event: BaseGestureEvent, _: GestureRecognizer, other: Array) => { - if (other && other.length > 0) { + if (this.isSmartFind && this.currentRecognizer == undefined) { + let lastRecognizer = other[other.length - 1] + if (lastRecognizer.getTag() == 'actionRefresh') { + this.currentRecognizer = lastRecognizer + } + } + if (this.currentRecognizer == undefined && other && other.length > 0) { for (let i = 0; i < other.length; i++) { if (other[i].getTag() == "actionRefresh" && other[i].getEventTargetInfo().getId() == this.currentId) { this.currentRecognizer = other[i] @@ -303,9 +339,11 @@ export struct ElfRefreshComponent { if (panEvent.offsetY > 0) { this.childRecognizer.setEnabled(false) this.currentRecognizer.setEnabled(true) + return GestureJudgeResult.REJECT } else { this.childRecognizer.setEnabled(true) this.currentRecognizer.setEnabled(false) + return GestureJudgeResult.REJECT } } else { this.childRecognizer.setEnabled(true) @@ -396,6 +434,9 @@ export struct ElfRefreshComponent { this.touchYOld = event.offsetY }) .onActionUpdate((event: GestureEvent) => { + if (this.isNest) { + return + } this.onActionUpdate(event.offsetY) }) .onActionCancel(() => { @@ -491,6 +532,7 @@ export struct ElfRefreshComponent { * 手势操作结束 */ private onActionEnd(): void { + this.isNest = false if (this.trYTop > 0) { // 下拉结束 if (this.state == RefreshState.IS_PULL_DOWN_REFRESH) { this.closeRefresh(); @@ -529,9 +571,9 @@ export struct ElfRefreshComponent { this.openTwo() return } else if (this.state == RefreshState.IS_TWO_LEVEL) { - if(this.trYTop <= LengthUtil.parseToVP(this.refreshConfigurator.getCloseTwoOffset(),this.twoHeader.height)){ + if (this.trYTop <= LengthUtil.parseToVP(this.refreshConfigurator.getCloseTwoOffset(), this.twoHeader.height)) { this.closeRefresh() - }else{ + } else { this.openTwo() } return