diff --git a/README.md b/README.md index 5367bd206386b8a283dff5ad7d3424903dd2e76d..45d0eb671fbe8aa374ad3b85d4f9d2c53b5562e1 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,16 @@ ```shell ohpm install @ohos/pulltorefresh ``` +## 使用限制 + +- 目前只支持List、Scroll、Tabs、Grid、和WaterFlow系统容器组件 ## 使用说明 ### 快速使用 ```typescript -import { RefreshList,RefreshGrid,RefreshScroll,RefreshWaterFlow, PullToRefreshConfigurator } from '@ohos/pulltorefresh' +import {PullToRefreshConfigurator, PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh' //动态添加list组件的属性 class MyListModifier implements AttributeModifier { @@ -30,41 +33,45 @@ class MyListModifier implements AttributeModifier { instance.divider({ strokeWidth: 1, color: 0x222222 }); } } -//RefreshGrid,RefreshScroll,RefreshWaterFlow组件参考如下RefreshList -RefreshList({ -// 必传项,列表组件所绑定的数据 -data: $data, -//必传项,控制是否进行下拉刷新 -refreshing:$refreshing, -// 必传项,自定义主体布局,内部有列表或宫格组件 -customList: () => { - // 一个用@Builder修饰过的UI方法 - this.getListView(); -}, -//可选项,属性方法修改时触发 -modifier:this.modifier, -// 可选项,下拉刷新回调 -onRefresh: () => { - return new Promise((resolve, reject) => { - // 模拟网络请求操作,请求网络1秒后得到数据,通知组件,变更列表数据 - setTimeout(() => { - resolve('刷新成功'); - this.data = this.dataNumbers; - }, 1000); - }); -}, -// 可选项,上拉加载更多回调 -onLoadMore: () => { - return new Promise((resolve, reject) => { - // 模拟网络请求操作,请求网络1秒后得到数据,通知组件,变更列表数据 - setTimeout(() => { - resolve(''); - this.data.push("增加的条目" + this.data.length); - }, 1000); - }); -}, -customLoad: null, -customRefresh: null, + +PullToRefresh({ + //容器主体布局类型 + pullToRefreshType:PullToRefreshType.LIST, + //必传项,控制是否进行下拉刷新 + refreshing: $refreshing, + // 必传项,需绑定传入主体布局内的列表或宫格组件 + customList: () => { + // 一个用@Builder修饰过的UI方法 + this.getListView(); + }, + // 可选项,组件属性配置,具有默认值 + refreshConfigurator: this.refreshConfigurator, + //可选项,属性方法修改时触发 + modifierListAttribute: this.modifier, + //可选项,下拉刷新回调 + onRefresh: () => { + return new Promise((resolve, reject) => { + // 模拟网络请求操作,请求网络1秒后得到数据,通知组件,变更列表数据 + this.timer = setTimeout(() => { + resolve('刷新成功'); + this.data = [...this.dataNumbers]; + }, 1000); + }); + }, + // 可选项,上拉加载更多回调 + onLoadMore: () => { + return new Promise((resolve, reject) => { + // 模拟网络请求操作,请求网络1秒后得到数据,通知组件,变更列表数据 + this.timer = setTimeout(() => { + resolve(''); + for (let index = 0; index < 10; index++) { + this.data.push("增加的条目" + this.data.length); + } + }, 1000); + }); + }, + customLoad: null, + customRefresh: null, }) ``` 以上系统组件的属性和方法的设置请参考[动态属性设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-attribute-modifier.md) @@ -106,8 +113,7 @@ interface DataChangeListener { | 属性 | 类型 | 释义 | 默认值 | |:-------------------:| :-------------------------------------------------------------: |:------------------:| :----------------------------: | -| data | Object[] | 列表或宫格组件所绑定的数据 | undefined | -| modifier | AttributeModifier | 动态修改组件的属性 | undefined | +| data | Object[]或undefined | 列表或宫格组件所绑定的数据 | undefined | | customList | ```() => void ``` | 自定义主体布局,内部有列表或宫格组件 | undefined | | refreshConfigurator | PullToRefreshConfigurator | 组件属性配置 | PullToRefreshConfigurator | | refreshHeight | Length | 触发下拉刷新的偏移量 | undefined | @@ -121,6 +127,13 @@ interface DataChangeListener { | customLoad | ```() => void``` | 自定义上拉加载动画布局 | undefined | | onRefreshSpringBack | ```(value?: number, height?: number) => void``` | 回弹的回调 | undefined | | refreshing | boolean | 控制是否进行下拉刷新 | undefined | +| modifierListAttribute | AttributeModifier | 动态修改List组件的属性 | undefined | +| modifierGridAttribute | AttributeModifier | 动态修改Grid组件的属性 | undefined | +| modifierScrollAttribute | AttributeModifier | 动态修改Scroll组件的属性 | undefined | +| modifierWaterFlowAttribute | AttributeModifier | 动态修改WaterFlow组件的属性 | undefined | +| pullToRefreshType | PullToRefreshType | 下拉刷新类型(枚举) | PullToRefreshType.LIST | +| gridDataLength | number | grid组件gridItem的数量 | undefined | +| layoutOptions | GridLayoutOptions | Grid组件滚动布局选项 | undefined | ### PullToRefreshConfigurator类接口 @@ -151,7 +164,7 @@ interface DataChangeListener { ## 约束与限制 在下述版本验证通过: -- DevEco Studio 5.0 Canary3(5.0.3.300)--SDK:API12 +- DevEco Studio 5.0 Canary3(5.0.3.403)--SDK:API12 ## 贡献代码 diff --git a/entry/src/main/ets/pages/customConfig.ets b/entry/src/main/ets/pages/customConfig.ets index c26baff72c1e8fe145cadb491993b0eeb0c8684e..e516658727920597447615ab44acd2a1f393b896 100644 --- a/entry/src/main/ets/pages/customConfig.ets +++ b/entry/src/main/ets/pages/customConfig.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshList, PullToRefreshConfigurator } from '@ohos/pulltorefresh' +import {PullToRefreshConfigurator, PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh' //动态添加list组件的属性 class MyListModifier implements AttributeModifier { @@ -56,9 +56,9 @@ struct Index { build() { Column() { - RefreshList({ - // 必传项,列表组件所绑定的数据 - data: $data, + PullToRefresh({ + //容器主体布局类型 + pullToRefreshType:PullToRefreshType.LIST, //必传项,控制是否进行下拉刷新 refreshing: $refreshing, // 必传项,需绑定传入主体布局内的列表或宫格组件 @@ -69,7 +69,7 @@ struct Index { // 可选项,组件属性配置,具有默认值 refreshConfigurator: this.refreshConfigurator, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierListAttribute: this.modifier, //可选项,下拉刷新回调 onRefresh: () => { return new Promise((resolve, reject) => { diff --git a/entry/src/main/ets/pages/customRefreshAnim.ets b/entry/src/main/ets/pages/customRefreshAnim.ets index dd499a5d719e1344ebf93e1d8a21b39dd6d8b1bb..6c775334bdf50da2a497425594c826cf7e51d4a5 100644 --- a/entry/src/main/ets/pages/customRefreshAnim.ets +++ b/entry/src/main/ets/pages/customRefreshAnim.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshList } from '@ohos/pulltorefresh' +import { PullToRefresh, PullToRefreshType} from '@ohos/pulltorefresh' const pointSpace = 30; const pointJitterAmplitude = 10; @@ -41,9 +41,9 @@ struct Index { build() { Column() { - RefreshList({ - // 必传项,列表组件所绑定的数据 - data: $data, + PullToRefresh({ + //容器主体布局类型 + pullToRefreshType:PullToRefreshType.LIST, //必传项,控制是否进行下拉刷新 refreshing: $refreshing, // 必传项,需绑定传入主体布局内的列表或宫格组件的item @@ -52,11 +52,11 @@ struct Index { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierListAttribute: this.modifier, // 可选项,下拉刷新回调 onRefresh: () => { return new Promise((resolve, reject) => { - // 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据 + // 模拟网络请求操作,请求网络1秒后得到数据,通知组件,变更列表数据 this.timer = setTimeout(() => { resolve('刷新成功'); this.data = [...this.dataNumbers]; diff --git a/entry/src/main/ets/pages/fullScreen.ets b/entry/src/main/ets/pages/fullScreen.ets index 86a1af34675a8298959646b0ddcdb60b2a560326..9d602a423c2a1a5fc47450d6acff4662c4599b28 100644 --- a/entry/src/main/ets/pages/fullScreen.ets +++ b/entry/src/main/ets/pages/fullScreen.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshList, PullToRefreshConfigurator } from '@ohos/pulltorefresh' +import { PullToRefreshConfigurator, PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh' //动态添加list组件的属性 class MyListModifier implements AttributeModifier { @@ -39,9 +39,9 @@ struct Index { } build() { Column() { - RefreshList({ - // 必传项,列表组件所绑定的数据 - data: $data, + PullToRefresh({ + //容器主体布局类型 + pullToRefreshType:PullToRefreshType.LIST, //必传项,控制是否进行下拉刷新 refreshing: $refreshing, // 必传项,需绑定传入主体布局内的列表或宫格组件的item @@ -50,7 +50,7 @@ struct Index { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierListAttribute: this.modifier, // 可选项,组件属性配置,具有默认值 refreshConfigurator: this.refreshConfigurator, //可选项,下拉刷新回调 diff --git a/entry/src/main/ets/pages/gridTestPage.ets b/entry/src/main/ets/pages/gridTestPage.ets index 430cda464c829aa8c795eac2882a989071364f8d..0f4e26b98cde3066fafb09c6162dd5dc73171c28 100644 --- a/entry/src/main/ets/pages/gridTestPage.ets +++ b/entry/src/main/ets/pages/gridTestPage.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshGrid } from '@ohos/pulltorefresh' +import { PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh' //动态添加list组件的属性 class MyGridModifier implements AttributeModifier { @@ -35,15 +35,18 @@ struct Index { private timer: null | number = null; @State layoutOptions: GridLayoutOptions = { regularSize: [1, 1], - irregularIndexes: [this.data.length * this.data.length], //this.data.length * this.data.length为必须项 + irregularIndexes: [this.data.length * this.data.length], //需传入gridItem的数量 }; build() { Stack() { - RefreshGrid({ + PullToRefresh({ + //可选,gridItem的数量,为grid的必传项 + gridDataLength: this.data.length * this.data.length, + //Grid组件滚动布局选项 layoutOptions: this.layoutOptions, - // 必传项,列表组件所绑定的数据 - data: $data, + //容器主体布局类型 + pullToRefreshType: PullToRefreshType.GRID, //必传项,控制是否进行下拉刷新 refreshing: $refreshing, // 必传项,需绑定传入主体布局内的列表或宫格组件 @@ -52,7 +55,7 @@ struct Index { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierGridAttribute: this.modifier, //可选项,下拉刷新回调 onRefresh: () => { return new Promise((resolve, reject) => { diff --git a/entry/src/main/ets/pages/index.ets b/entry/src/main/ets/pages/index.ets index 9699ef978b5bb569a68f3fded4201382af4de26d..fdf208b5a4b1a345ff78894100877be508fac60c 100644 --- a/entry/src/main/ets/pages/index.ets +++ b/entry/src/main/ets/pages/index.ets @@ -13,6 +13,7 @@ * limitations under the License. */ import router from '@ohos.router'; + @Entry @Component struct Index { diff --git a/entry/src/main/ets/pages/lazyForEachGuide.ets b/entry/src/main/ets/pages/lazyForEachGuide.ets index ae4c5ba8785336f4902e9c4214cd5c4dd50bd27c..600836af7b1550dc14fce2c93043164d81eec6b6 100644 --- a/entry/src/main/ets/pages/lazyForEachGuide.ets +++ b/entry/src/main/ets/pages/lazyForEachGuide.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshList } from '@ohos/pulltorefresh'; +import { PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh'; class BasicDataSource implements IDataSource { private listeners: DataChangeListener[] = new Array(); @@ -127,9 +127,9 @@ struct Index { build() { Stack() { - RefreshList({ - // 必传项,列表组件所绑定的数据 - data: $data, + PullToRefresh({ + //容器主题布局类型 + pullToRefreshType:PullToRefreshType.LIST, //必传项,控制是否进行下拉刷新 refreshing: $refreshing, // 必传项,自定义主体布局,内部有列表或宫格组件 @@ -138,7 +138,7 @@ struct Index { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierListAttribute: this.modifier, // 可选项,下拉刷新回调 onRefresh: () => { return new Promise((resolve, reject) => { diff --git a/entry/src/main/ets/pages/quickStart.ets b/entry/src/main/ets/pages/quickStart.ets index 622afc76ae64985354f126fc3f4a7a05709e5d02..03a39a1afa2cbefa2febe8a5bc6e6aa8ec21fa43 100644 --- a/entry/src/main/ets/pages/quickStart.ets +++ b/entry/src/main/ets/pages/quickStart.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshList } from '@ohos/pulltorefresh' +import { PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh' //动态添加list组件的属性 class MyListModifier implements AttributeModifier { @@ -25,7 +25,6 @@ class MyListModifier implements AttributeModifier { @Component struct Index { @State refreshing: boolean = false; - @State refreshText: string = ''; private dataNumbers: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']; private dataStrings: string[] = ['我的评论', '与我相关', '个人中心1', '个人中心2', '个人中心3', '我的发布', '设置', '退出登录']; @State data: string[] = this.dataStrings; @@ -34,9 +33,9 @@ struct Index { build() { Column() { - RefreshList({ - // 必传项,列表组件所绑定的数据 - data: $data, + PullToRefresh({ + //容器主体布局类型 + pullToRefreshType:PullToRefreshType.LIST, //必传项,控制是否进行下拉刷新 refreshing: $refreshing, // 必传项,需绑定传入主体布局内的列表或宫格组件 @@ -45,7 +44,7 @@ struct Index { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierListAttribute: this.modifier, // 可选项,下拉刷新回调 onRefresh: () => { return new Promise((resolve, reject) => { diff --git a/entry/src/main/ets/pages/scrollTestPage.ets b/entry/src/main/ets/pages/scrollTestPage.ets index 828092cee946e802f418c0c6f27406d705b4e2de..5e1fcf4ff8c520cd960e65250254228d35d8009a 100644 --- a/entry/src/main/ets/pages/scrollTestPage.ets +++ b/entry/src/main/ets/pages/scrollTestPage.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshScroll, PullToRefreshConfigurator } from '@ohos/pulltorefresh' +import {PullToRefreshConfigurator, PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh' //动态添加scroll组件的属性 class MyScrollModifier implements AttributeModifier { @@ -20,10 +20,6 @@ class MyScrollModifier implements AttributeModifier { instance.backgroundColor('#DCDCDC'); instance.friction(0.6); instance.align(Alignment.TopStart); - instance.nestedScroll({ - scrollForward: NestedScrollMode.PARENT_FIRST, - scrollBackward: NestedScrollMode.SELF_FIRST - }) } } @@ -68,7 +64,7 @@ struct TabsExample { Column().width('100%').height('100%').backgroundColor('#007DFF') }.tabBar(this.TabBuilder(1, 'tab2')) } - .height('100%') + .height('60%') .vertical(false) .barMode(BarMode.Fixed) .barWidth(360) @@ -109,11 +105,11 @@ struct PullToRefreshDemo { build() { Column() { - RefreshScroll({ - // 必传项,列表组件所绑定的数据 - data: $data, + PullToRefresh({ //必传项,控制是否进行下拉刷新 refreshing: $refreshing, + //容器主体布局类型 + pullToRefreshType:PullToRefreshType.SCROLL, //可选项,组件属性配置,具有默认值 refreshConfigurator: this.refreshConfigurator, // 必传项,需绑定传入主体布局内的列表或宫格组件的item @@ -122,7 +118,7 @@ struct PullToRefreshDemo { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierScrollAttribute: this.modifier, // 可选项,下拉刷新回调 onRefresh: () => { return new Promise((resolve, reject) => { @@ -167,10 +163,6 @@ struct PullToRefreshDemo { .width("100%") .margin({ top: 10 }) .edgeEffect(EdgeEffect.Spring) - .nestedScroll({ - scrollForward: NestedScrollMode.PARENT_FIRST, - scrollBackward: NestedScrollMode.SELF_FIRST - }) } aboutToDisAppear() { diff --git a/entry/src/main/ets/pages/tabsTestPage.ets b/entry/src/main/ets/pages/tabsTestPage.ets index 8770c53b831d52bba6e308341734730a2d1ae9b2..d571b4d1b173f10ee6086f671ec643d5d55ad1cb 100644 --- a/entry/src/main/ets/pages/tabsTestPage.ets +++ b/entry/src/main/ets/pages/tabsTestPage.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshList } from '@ohos/pulltorefresh' +import { PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh' //动态添加list组件的属性 class MyListModifier implements AttributeModifier { @@ -90,9 +90,9 @@ struct PullToRefreshDemo { build() { Stack() { - RefreshList({ - // 必传项,列表组件所绑定的数据 - data: $data, + PullToRefresh({ + //容器主体布局类型 + pullToRefreshType:PullToRefreshType.LIST, //必传项,控制是否进行下拉刷新 refreshing: $refreshing, // 必传项,需绑定传入主体布局内的列表或宫格组件的item @@ -101,14 +101,14 @@ struct PullToRefreshDemo { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierListAttribute: this.modifier, // 可选项,下拉刷新回调 onRefresh: () => { return new Promise((resolve, reject) => { // 模拟网络请求操作,请求网络1秒后得到数据,通知组件,变更列表数据 setTimeout(() => { resolve('刷新成功'); - this.data = this.dataNumbers; + this.data = [...this.dataNumbers]; }, 1000); }); }, diff --git a/entry/src/main/ets/pages/testPullCallback.ets b/entry/src/main/ets/pages/testPullCallback.ets index 4947d6beba689405875629fcc9b2c51439d453c1..c97e0ea12e6c4fbb963b344adf4b362e033488b2 100644 --- a/entry/src/main/ets/pages/testPullCallback.ets +++ b/entry/src/main/ets/pages/testPullCallback.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshList, PullToRefreshConfigurator } from '@ohos/pulltorefresh'; +import {PullToRefreshConfigurator, PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh'; //动态添加list组件的属性 class MyListModifier implements AttributeModifier { @@ -30,7 +30,6 @@ const topImageSize = 15; @Component struct Index { @State stop: boolean = false; - start: Boolean[] = [false, false, false]; @State refreshing: boolean = false; private dataNumbers: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']; private dataStrings: string[] = ['我的评论', '与我相关', '个人中心1', '个人中心2', '个人中心3', '我的发布', '设置', '退出登录']; @@ -50,9 +49,9 @@ struct Index { build() { Column() { - RefreshList({ - //必传项,列表组件所绑定的数据 - data: $data, + PullToRefresh({ + //容器主体布局类型 + pullToRefreshType:PullToRefreshType.LIST, //必传项,控制是否进行下拉刷新 refreshing: $refreshing, //必传项,需绑定传入主体局内的列表或宫格组件的item @@ -61,7 +60,7 @@ struct Index { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierListAttribute: this.modifier, //可选项,自定义下拉刷新动画布局 customRefresh: () => { this.customRefreshView(); diff --git a/entry/src/main/ets/pages/waterFlowTestPage.ets b/entry/src/main/ets/pages/waterFlowTestPage.ets index dd9586939238b7d4e12da0828c893780abeec50c..b667a46116a29654645540b6f95ac7d132d1a32d 100644 --- a/entry/src/main/ets/pages/waterFlowTestPage.ets +++ b/entry/src/main/ets/pages/waterFlowTestPage.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { RefreshWaterFlow } from '@ohos/pulltorefresh'; +import { PullToRefresh,PullToRefreshType } from '@ohos/pulltorefresh'; //实现IDataSource接口的对象,用于瀑布流组件加载数据 class WaterFlowDataSource implements IDataSource { @@ -196,9 +196,9 @@ struct Index { build() { Stack() { - RefreshWaterFlow({ - //必传项,列表组件所绑定的数据 - data: $dataSource, + PullToRefresh({ + //容器主题布局类型 + pullToRefreshType:PullToRefreshType.WATERFLOW, //必传项,控制是否刷新 refreshing: $refreshing, //必传项,需绑定传入主体布局内的列表或宫格组件的item @@ -207,7 +207,7 @@ struct Index { this.getListView(); }, //可选项,属性方法修改时触发 - modifier: this.modifier, + modifierWaterFlowAttribute: this.modifier, //可选项,下拉刷新回调 onRefresh: () => { return new Promise((resolve, reject) => { diff --git a/gifs/Refresh.gif b/gifs/Refresh.gif index 15b471f0b746e24baa7823d9738d209b85e0b66b..42ffd94b6d9db361b4cfbf9e3237a9d9d1198764 100644 Binary files a/gifs/Refresh.gif and b/gifs/Refresh.gif differ diff --git a/library/index.ets b/library/index.ets index 6e10b8143df26fd2ca3b3e38c613f534285ab661..aa399893363950e0e094f02e96e1ae9ded90c260 100644 --- a/library/index.ets +++ b/library/index.ets @@ -14,13 +14,9 @@ */ export { PullToRefreshConfigurator } from './src/main/ets/components/PullToRefresh/PullToRefreshConfigurator' -export { RefreshList } from './src/main/ets/components/PullToRefresh/RefreshList' +export { PullToRefresh} from './src/main/ets/components/PullToRefresh/PullToRefresh' -export { RefreshGrid } from './src/main/ets/components/PullToRefresh/RefreshGrid' - -export { RefreshWaterFlow } from './src/main/ets/components/PullToRefresh/RefreshWaterFlow' - -export { RefreshScroll } from './src/main/ets/components/PullToRefresh/RefreshScroll' +export { PullToRefreshType} from './src/main/ets/components/utils/PullToRefreshType' diff --git a/library/src/main/ets/components/PullToRefresh/RefreshGrid.ets b/library/src/main/ets/components/PullToRefresh/GridComponent.ets similarity index 30% rename from library/src/main/ets/components/PullToRefresh/RefreshGrid.ets rename to library/src/main/ets/components/PullToRefresh/GridComponent.ets index e1411e3cc38ae9a2eba796934e21f586800dab9b..06a930e818a561d01c61321dfb55a2dc99f01c85 100644 --- a/library/src/main/ets/components/PullToRefresh/RefreshGrid.ets +++ b/library/src/main/ets/components/PullToRefresh/GridComponent.ets @@ -16,183 +16,45 @@ import { PullToRefreshConfigurator } from './PullToRefreshConfigurator'; @Component -export struct RefreshGrid { +export struct GridComponent { + //Grid组件滚动布局选项 @Link layoutOptions: GridLayoutOptions; // 动态修改list组件的属性 modifier?: AttributeModifier; + //gridItem的数量 + @Prop @Watch('dataChange') gridDataLength: number; // 源数据 - @Link data: Object[]; - // 控制组件是否正在刷新 - @Link refreshing: boolean; - // 默认动画的value值 - @State refreshOffset: number = 0; - // 偏移距离 - private rangeValue: number = 64; - // 刷新过程参数 - @State refreshState: RefreshStatus = RefreshStatus.Inactive; + @Prop data: Object[]; // 是否触发上拉加载 - @State isTriggerPullUpLoading: boolean = false; + @Link isTriggerPullUpLoading: boolean; // 可滚动组件的控制器 private scroller: Scroller = new Scroller(); - // 回弹的回调 - onRefreshSpringBack?: (value?: number, height?: number) => void; // 组件属性配置 refreshConfigurator?: PullToRefreshConfigurator; - // 下拉刷新成功提示文本 - @State private refreshText?: string = '成功'; // 上拉加载图片旋转参数 - @State private angle?: number | string = 0; - // 定时器 - private timer?: number; + @Prop angle: number | string; // 自定义组件主体布局 @BuilderParam customList?: () => void; - // 自定义下拉动画 - @BuilderParam customRefresh?: (() => void) | null; // 自定义上拉动画 @BuilderParam customLoad?: (() => void) | null; - @State private lastIndex: number = 0; - // 下拉刷新回调 - onRefresh?: () => Promise = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve('刷新失败'); - }, 1000); - }); - }; // 上拉刷新回调 - onLoadMore?: () => Promise = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(''); - }, 1000); - }); - }; - // 开启自定义下拉动画 - onAnimPullDown?: (value?: number, width?: number, height?: number) => void; - onAnimRefreshing?: (value?: number, width?: number, height?: number, isOnAnimRefreshing?: boolean) => void; - private refreshAnimDurationValue?: number = 0; - private mWidthNumber?: number = 0; - // 开启自定义上拉动画 - private loadAnimDurationValue?: number = 0; - private loadVisible?: Boolean = false; - private onLoadAnimDuration?: number = 0; - onAnimLoading?: (value?: number, width?: number, height?: number) => void; + onLoadMore?: () => Promise; + // 组件的宽度 + @Link mWidthNumber: number; + // 是否显示上拉加载动画 + @Link loadVisible: Boolean; - aboutToAppear() { - if (!this.refreshConfigurator) { - this.refreshConfigurator = new PullToRefreshConfigurator(); - } - this.timer = setInterval(() => { - //下拉阶段动画 - if (this.onAnimPullDown && (this.refreshState == RefreshStatus.Drag || this.refreshState == RefreshStatus.OverDrag && this.refreshConfigurator)) { - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - let value = this.refreshOffset > rangeHeightValue ? rangeHeightValue : this.refreshOffset; - this.onAnimPullDown(value / rangeHeightValue, this.mWidthNumber, this.refreshOffset) - } - //Refresh阶段动画 - if (this.refreshState == RefreshStatus.Refresh) { - let refreshAnimDuration = this.refreshConfigurator?.getRefreshAnimDuration(); - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - if (this.refreshAnimDurationValue !== undefined) { - if (this.refreshAnimDurationValue >= 1) { - this.refreshAnimDurationValue -= 1; - } else { - if (refreshAnimDuration !== undefined && refreshAnimDuration !== 0) { - this.refreshAnimDurationValue += 10 / refreshAnimDuration; - } - } - // 保留3位小数 - this.refreshAnimDurationValue = Math.round(this.refreshAnimDurationValue * 1000) / 1000; - } - // 如果又刷新中动画回调,就执行刷新中动画回调 - if (this.onAnimRefreshing) { - this.onAnimRefreshing(this.refreshAnimDurationValue, this.mWidthNumber, rangeHeightValue); - } - } - //Refresh结束回到顶部阶段 - if (this.refreshState == RefreshStatus.Done) { - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - if (this.rangeValue !== undefined && this.rangeValue > 0) { - this.rangeValue -= 5; //注意这个地方应该用速度状态进行判断 - if (this.onRefreshSpringBack) { - this.onRefreshSpringBack(this.rangeValue, rangeHeightValue) - } - } - } - //上拉动画 - if (this.onLoadMore !== undefined && this.isTriggerPullUpLoading && this.loadVisible) { - //内置上拉动画 - if (this.loadAnimDurationValue !== undefined && !this.customLoad) { - if (this.loadAnimDurationValue >= 1) { - this.loadAnimDurationValue -= 1; - } else { - this.loadAnimDurationValue += 0.01; - } - // 保留2位小数 - this.loadAnimDurationValue = Math.round(this.loadAnimDurationValue * 100) / 100; - this.angle = this.loadAnimDurationValue * 360; - } - //自定义上拉动画 - if (this.onLoadAnimDuration !== undefined && this.customLoad && this.onAnimLoading) { - let loadAnimDuration = this.refreshConfigurator?.getLoadAnimDuration(); - let loadHeightValue = this.refreshConfigurator?.getLoadImageHeight() as number; - if (this.onLoadAnimDuration >= 1) { - this.onLoadAnimDuration -= 1; - } else { - if (loadAnimDuration !== undefined && loadAnimDuration !== 0) { - this.onLoadAnimDuration += 10 / loadAnimDuration; - } - } - // 保留3位小数 - this.onLoadAnimDuration = Math.round(this.onLoadAnimDuration * 1000) / 1000; - this.onAnimLoading(this.onLoadAnimDuration, this.mWidthNumber, loadHeightValue); - } - } - }, 7) - } - - aboutToDisappear() { - clearInterval(this.timer); - } - - @Builder - refreshBuilder() { - Stack({ alignContent: Alignment.Center }) { - if (this.customRefresh !== undefined && this.customRefresh !== null) { - Row(){ - this.customRefresh(); - } - .visibility((this.refreshOffset > 0 && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) - } else { - Row() { - Progress({ - value: this.refreshOffset, - total: this.refreshConfigurator?.getRefreshHeight(), - type: ProgressType.Ring - }) - .width(32) - .height(32) - .margin(10) - .color(this.refreshConfigurator?.getRefreshColor()) - .style({ - status: this.refreshing ? ProgressStatus.LOADING : ProgressStatus.PROGRESSING, - enableScanEffect: true - }) - Text('正在刷新...') - .fontSize(this.refreshConfigurator?.getRefreshTextSize()) - .margin({ left: 20 }) - .fontColor(this.refreshConfigurator?.getRefreshTextColor()) - } - Image(this.refreshConfigurator?.getRefreshBackgroundImage()) - .opacity(this.refreshConfigurator?.getRefreshOpacity()) - } - } - .width('100%') - .visibility((this.refreshConfigurator?.getHasRefresh() && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) + dataChange() { + //用this.data.length * this.data.length长度替换irregularIndexes数组的最后一个元素 + this.layoutOptions.irregularIndexes?.pop(); + this.layoutOptions?.irregularIndexes?.push(this.gridDataLength); + // //重新给 irregularIndexes 赋值,否则最后一行UI不刷新 + this.layoutOptions?.irregularIndexes && + (this.layoutOptions.irregularIndexes = [...this.layoutOptions.irregularIndexes]) } build() { - Refresh({ refreshing: $$this.refreshing, builder: this.refreshBuilder() }) { + Column() { Grid(this.scroller, this.layoutOptions) { if (this.customList !== undefined) { this.customList(); @@ -229,7 +91,7 @@ export struct RefreshGrid { .width('100%') .height(this.refreshConfigurator?.getLoadImageHeight()) .backgroundColor(this.refreshConfigurator?.getLoadBackgroundColor()) - .visibility(this.isTriggerPullUpLoading ? Visibility.Visible : Visibility.None) + .visibility((this.isTriggerPullUpLoading === undefined || !this.isTriggerPullUpLoading) ? Visibility.None : Visibility.Visible) .onVisibleAreaChange([0.2], (isVisible: boolean, currentRatio: number) => { this.loadVisible = isVisible; if (isVisible && this.onLoadMore !== undefined) { @@ -240,16 +102,6 @@ export struct RefreshGrid { .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true }) .backgroundColor(this.refreshConfigurator?.getSubjectContentBackgroundColor()) - .onScrollIndex((first: number, last: number) => { - this.lastIndex = last; - }) - .onScrollStart(() => { - //用this.data.length * this.data.length长度替换irregularIndexes数组的最后一个元素 - this.layoutOptions.irregularIndexes?.pop(); - this.layoutOptions.irregularIndexes?.push(this.data.length * this.data.length); - //重新给 irregularIndexes 赋值,否则最后一行UI不刷新 - this.layoutOptions.irregularIndexes && (this.layoutOptions.irregularIndexes = [...this.layoutOptions.irregularIndexes]) - }) .onWillScroll((scrollOffset: number) => { if (!this.isTriggerPullUpLoading && this.refreshConfigurator !== undefined && this.refreshConfigurator.getHasLoadMore() && scrollOffset > 0) { this.isTriggerPullUpLoading = true; @@ -258,29 +110,8 @@ export struct RefreshGrid { .attributeModifier(this.modifier) .onAreaChange((oldValue: Area, newValue: Area) => { this.mWidthNumber = Math.round(newValue.width as number); - this.refreshOffset = newValue.position.y as number; }) } - .width('100%') - .height('100%') - .refreshOffset(this.refreshConfigurator?.getRefreshHeight()) - .pullToRefresh(this.refreshConfigurator?.getHasRefresh()) - .backgroundColor(this.refreshConfigurator?.getHasRefresh() ? this.refreshConfigurator?.getRefreshBackgroundColor():'') - .onStateChange((state: RefreshStatus) => { - this.refreshState = state; - if (this.refreshState == RefreshStatus.Done) { - this.rangeValue = this.refreshConfigurator?.getRefreshHeight() as number; - } - }) - .onRefreshing(() => { - // 下拉刷新回调 - if (this.onRefresh !== undefined) { - this.onRefresh().then((refreshText) => { - this.refreshText = refreshText; - this.refreshing = false; - }) - } - }) } // 上拉加载回调 @@ -289,9 +120,6 @@ export struct RefreshGrid { // 上拉加载完成回调 this.onLoadMore().then(() => { this.isTriggerPullUpLoading = false; - this.layoutOptions.irregularIndexes?.pop(); - this.layoutOptions.irregularIndexes?.push(this.data.length * this.data.length); - this.layoutOptions.irregularIndexes && (this.layoutOptions.irregularIndexes = [...this.layoutOptions.irregularIndexes]) }) } } diff --git a/library/src/main/ets/components/PullToRefresh/RefreshList.ets b/library/src/main/ets/components/PullToRefresh/ListComponent.ets similarity index 36% rename from library/src/main/ets/components/PullToRefresh/RefreshList.ets rename to library/src/main/ets/components/PullToRefresh/ListComponent.ets index fdd73b720775ef6a4101135870e7ecd2418dfce9..1b8411ca5e5efaf85abaa8ba586fdbc971512eef 100644 --- a/library/src/main/ets/components/PullToRefresh/RefreshList.ets +++ b/library/src/main/ets/components/PullToRefresh/ListComponent.ets @@ -12,188 +12,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { PullToRefreshConfigurator } from './PullToRefreshConfigurator'; @Component -export struct RefreshList { +export struct ListComponent { // 动态修改list组件的属性 modifier?: AttributeModifier; // 源数据 - @Link data: Object[]; - // 控制组件是否正在刷新 - @Link refreshing: boolean; - // 默认动画的value值 - @State refreshOffset: number = 0; - // 刷新过程参数 - @State refreshState: RefreshStatus = RefreshStatus.Inactive; + @Prop data: Object[]; // 是否触发上拉加载 - @State isTriggerPullUpLoading: boolean = false; + @Link isTriggerPullUpLoading: boolean; // 可滚动组件的控制器 private scroller: Scroller = new Scroller(); // 组件属性配置 refreshConfigurator?: PullToRefreshConfigurator; - // 下拉刷新成功提示文本 - @State private refreshText?: string = ''; // 上拉加载图片旋转参数 - @State private angle?: number | string = 0; - // 定时器 - private timer?: number; - // 偏移距离 - private rangeValue: number = 64; + @Prop angle: number | string; // 自定义组件主体布局 @BuilderParam customList?: () => void; - // 自定义下拉动画 - @BuilderParam customRefresh?: (() => void) | null; // 自定义上拉动画 @BuilderParam customLoad?: (() => void) | null; - // 下拉刷新回调 - onRefresh?: () => Promise = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve('刷新失败'); - }, 1000); - }); - }; // 上拉刷新回调 - onLoadMore?: () => Promise = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(''); - }, 1000); - }); - }; - // 回弹的回调 - onRefreshSpringBack?: (value?: number, height?: number) => void; - // 开启自定义下拉动画 - onAnimPullDown?: (value?: number, width?: number, height?: number) => void; - onAnimRefreshing?: (value?: number, width?: number, height?: number) => void; - private refreshAnimDurationValue?: number = 0; - private mWidthNumber?: number = 0; - // 开启自定义上拉动画 - private loadAnimDurationValue?: number = 0; - private loadVisible?: Boolean = false; - private onLoadAnimDuration?: number = 0; + onLoadMore?: () => Promise; + //组件宽度 + @Link mWidthNumber: number; + //是否显示上拉加载 + @Link loadVisible: Boolean; + //控制全屏展示时,上拉加载完成后页面底部位置显示第几个listItem @State fullScreenScrollIndex: number = 0; - onAnimLoading?: (value?: number, width?: number, height?: number) => void; - - aboutToAppear() { - if (!this.refreshConfigurator) { - this.refreshConfigurator = new PullToRefreshConfigurator(); - } - this.timer = setInterval(() => { - //下拉阶段动画 - if (this.onAnimPullDown && (this.refreshState == RefreshStatus.Drag || this.refreshState == RefreshStatus.OverDrag && this.refreshConfigurator)) { - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - let value = this.refreshOffset > rangeHeightValue ? rangeHeightValue : this.refreshOffset; - this.onAnimPullDown(value / rangeHeightValue, this.mWidthNumber, this.refreshOffset) - } - //Refresh阶段动画 - if (this.refreshState == RefreshStatus.Refresh) { - let refreshAnimDuration = this.refreshConfigurator?.getRefreshAnimDuration(); - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - if (this.refreshAnimDurationValue !== undefined) { - if (this.refreshAnimDurationValue >= 1) { - this.refreshAnimDurationValue -= 1; - } else { - if (refreshAnimDuration !== undefined && refreshAnimDuration !== 0) { - this.refreshAnimDurationValue += 10 / refreshAnimDuration; - } - } - // 保留3位小数 - this.refreshAnimDurationValue = Math.round(this.refreshAnimDurationValue * 1000) / 1000; - } - // 如果又刷新中动画回调,就执行刷新中动画回调 - if (this.onAnimRefreshing) { - this.onAnimRefreshing(this.refreshAnimDurationValue, this.mWidthNumber, rangeHeightValue); - } - } - //Refresh结束回到顶部阶段 - if (this.refreshState == RefreshStatus.Done) { - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - if (this.rangeValue !== undefined && this.rangeValue > 0) { - this.rangeValue -= 5; - if (this.onRefreshSpringBack) { - this.onRefreshSpringBack(this.rangeValue, rangeHeightValue) - } - } - } - //上拉动画 - if (this.onLoadMore !== undefined && this.isTriggerPullUpLoading && this.loadVisible) { - //内置上拉动画 - if (this.loadAnimDurationValue !== undefined && !this.customLoad) { - if (this.loadAnimDurationValue >= 1) { - this.loadAnimDurationValue -= 1; - } else { - this.loadAnimDurationValue += 0.01; - } - // 保留2位小数 - this.loadAnimDurationValue = Math.round(this.loadAnimDurationValue * 100) / 100; - // 如果没有自定义加载中动画,就执行内置加载中动画 - this.angle = this.loadAnimDurationValue * 360; - } - //自定义上拉动画 - if (this.onLoadAnimDuration !== undefined && this.customLoad && this.onAnimLoading) { - let loadAnimDuration = this.refreshConfigurator?.getLoadAnimDuration(); - let loadHeightValue = this.refreshConfigurator?.getLoadImageHeight() as number; - if (this.onLoadAnimDuration >= 1) { - this.onLoadAnimDuration -= 1; - } else { - if (loadAnimDuration !== undefined && loadAnimDuration !== 0) { - this.onLoadAnimDuration += 10 / loadAnimDuration; - } - } - // 保留3位小数 - this.onLoadAnimDuration = Math.round(this.onLoadAnimDuration * 1000) / 1000; - this.onAnimLoading(this.onLoadAnimDuration, this.mWidthNumber, loadHeightValue); - } - } - }, 7) - } - - aboutToDisappear() { - clearInterval(this.timer); - } - - @Builder - refreshBuilder() { - Stack() { - if (this.customRefresh !== undefined && this.customRefresh !== null) { - Row(){ - this.customRefresh(); - } - .visibility((this.refreshOffset > 0 && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) - } else { - Row() { - Progress({ - value: this.refreshOffset, - total: this.refreshConfigurator?.getRefreshHeight(), - type: ProgressType.Ring - }) - .width(32) - .height(32) - .margin(10) - .color(this.refreshConfigurator?.getRefreshColor()) - .style({ - status: this.refreshing ? ProgressStatus.LOADING : ProgressStatus.PROGRESSING, - enableScanEffect: true - }) - Text('正在刷新...') - .fontSize(this.refreshConfigurator?.getRefreshTextSize()) - .margin({ left: 20 }) - .fontColor(this.refreshConfigurator?.getRefreshTextColor()) - } - Image(this.refreshConfigurator?.getRefreshBackgroundImage()) - .opacity(this.refreshConfigurator?.getRefreshOpacity()) - } - } - .width('100%') - .align(Alignment.Center) - .visibility((this.refreshConfigurator?.getHasRefresh() && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) - } build() { - Refresh({ refreshing: $$this.refreshing, builder: this.refreshBuilder() }) { + Column() { List({ initialIndex: this.refreshConfigurator?.getListInitialIndex(), space: this.refreshConfigurator?.getListSpace(), @@ -234,7 +83,7 @@ export struct RefreshList { .width('100%') .height(this.refreshConfigurator?.getLoadImageHeight()) .backgroundColor(this.refreshConfigurator?.getLoadBackgroundColor()) - .visibility(this.isTriggerPullUpLoading ? Visibility.Visible : Visibility.None) + .visibility((this.isTriggerPullUpLoading === undefined || !this.isTriggerPullUpLoading) ? Visibility.None : Visibility.Visible) .onVisibleAreaChange([0.2], (isVisible: boolean, currentRatio: number) => { this.loadVisible = isVisible; if (isVisible && this.onLoadMore !== undefined) { @@ -255,8 +104,7 @@ export struct RefreshList { }) .attributeModifier(this.modifier) // 动态设置属性 .onAreaChange((oldValue: Area, newValue: Area) => { - this.mWidthNumber = Math.round(newValue.width as number); - this.refreshOffset = newValue.position.y as number; + this.mWidthNumber = Math.round(newValue.width as number) as number; }) .onScrollIndex((start: number) => { if (this.refreshConfigurator?.getFullScreen()) { @@ -266,24 +114,6 @@ export struct RefreshList { } .width('100%') .height('100%') - .refreshOffset(this.refreshConfigurator?.getRefreshHeight()) - .pullToRefresh(this.refreshConfigurator?.getHasRefresh()) - .backgroundColor(this.refreshConfigurator?.getHasRefresh() ? this.refreshConfigurator?.getRefreshBackgroundColor():'') - .onStateChange((state: RefreshStatus) => { - this.refreshState = state; - if (state == RefreshStatus.Done) { - this.rangeValue = this.refreshConfigurator?.getRefreshHeight() as number; - } - }) - .onRefreshing(() => { - // 下拉刷新回调 - if (this.onRefresh !== undefined) { - this.onRefresh().then((refreshText) => { - this.refreshText = refreshText; - this.refreshing = false; - }) - } - }) } private onLoading() { diff --git a/library/src/main/ets/components/PullToRefresh/PullToRefresh.ets b/library/src/main/ets/components/PullToRefresh/PullToRefresh.ets new file mode 100644 index 0000000000000000000000000000000000000000..08512e3780aa17688550f83fb4edc832fcb7be38 --- /dev/null +++ b/library/src/main/ets/components/PullToRefresh/PullToRefresh.ets @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * 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. + */ +import { PullToRefreshType } from '../utils/PullToRefreshType'; +import { RefreshStateUtil } from '../utils/RefreshStateUtil'; +import { GridComponent } from './GridComponent'; +import { ListComponent } from './ListComponent'; +import { PullToRefreshConfigurator } from './PullToRefreshConfigurator'; +import { ScrollComponent } from './ScrollComponent'; +import { WaterFlowComponent } from './WaterFlowComponent'; + +@Component +export struct PullToRefresh { + //下拉刷新类型 默认值是PullToRefreshType.LIST + @Prop @Require pullToRefreshType: PullToRefreshType = PullToRefreshType.LIST; + // 动态修改各组件的属性 + modifierListAttribute?: AttributeModifier; + modifierGridAttribute?: AttributeModifier; + modifierScrollAttribute?: AttributeModifier; + modifierWaterFlowAttribute?: AttributeModifier; + // 源数据 + @Prop data?: Object[] | undefined = undefined; + // 控制组件是否正在刷新 + @Link refreshing: boolean; + // 组件属性配置 + refreshConfigurator?: PullToRefreshConfigurator; + // 自定义组件主体布局 + @BuilderParam customList?: () => void; + // 自定义下拉动画 + @BuilderParam customRefresh?: (() => void) | null; + // 自定义上拉动画 + @BuilderParam customLoad?: (() => void) | null; + // 下拉刷新回调 + onRefresh?: () => Promise = () => { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve('刷新失败'); + }, 1000); + }); + }; + // 上拉刷新回调 + onLoadMore?: () => Promise = () => { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(''); + }, 1000); + }); + }; + // 回弹的回调 + onRefreshSpringBack?: (value?: number, height?: number) => void; + // 开启自定义下拉动画 + onAnimPullDown?: (value?: number, width?: number, height?: number) => void; + onAnimRefreshing?: (value?: number, width?: number, height?: number) => void; + onAnimLoading?: (value?: number, width?: number, height?: number) => void; + //grid组件gridItem的数量 + @Prop gridDataLength: number; + //Grid组件滚动布局选项 + @Prop layoutOptions: GridLayoutOptions; + //-----------------------------以下为组件内自用属性-----------------------------// + // 默认动画的value值 + @State private refreshOffset: number = 0; + // 刷新过程参数 + @State private refreshState: RefreshStatus = RefreshStatus.Inactive; + // 是否触发上拉加载 + @State private isTriggerPullUpLoading: boolean = false; + // 上拉加载图片旋转参数 + @State private angle?: number | string = 0; + + @State private mWidthNumber?: number = 0; + // 开启自定义上拉动画 + @State private loadVisible: Boolean = false; + private loadAnimDurationValue?: number = 0; + private onLoadAnimDuration?: number = 0; + //刷新成功提示文本 + @State private refreshText?: string = ''; + @State private isShowRefreshText?: boolean = false; + // 定时器 + private timer?: number; + // 偏移距离 + private rangeValue: number = 64; + private refreshAnimDurationValue?: number = 0; + private canvasSetting?: RenderingContextSettings = new RenderingContextSettings(true); + private canvasRefresh?: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.canvasSetting); + private refreshRingOx?: number = 0; + private refreshRingOy?: number = 0; + private refreshRingRadius?: number = 0; + private refreshPoint1x?: number = 0; + private refreshPoint1y?: number = 0; + private refreshPoint2x?: number = 0; + private refreshPoint2y?: number = 0; + + aboutToAppear() { + if (!this.refreshConfigurator) { + this.refreshConfigurator = new PullToRefreshConfigurator(); + } + this.timer = setInterval(() => { + //Refresh下拉阶段 + RefreshStateUtil.onAnimPullDownFun( + this.refreshOffset, + this.refreshState, + this.onAnimPullDown, + this.refreshConfigurator, + this.mWidthNumber + ); + //Refresh阶段动画 + let onRefresh = RefreshStateUtil.onRefreshingFun( + this.refreshState, + this.refreshConfigurator, + this.refreshAnimDurationValue, + this.mWidthNumber, + this.onAnimRefreshing + ); + if (this.refreshAnimDurationValue !== undefined && this.refreshState === RefreshStatus.Refresh) { + this.refreshAnimDurationValue = onRefresh.x; + } + //Refresh结束回到顶部阶段 + this.rangeValue = RefreshStateUtil.onRefreshSpringBackFun( + this.rangeValue, + this.refreshState, + this.refreshConfigurator, + this.onRefreshSpringBack + ); + //上拉动画 + let onLoadingValue = RefreshStateUtil.onAnimLoadingFun( + this.isTriggerPullUpLoading, + this.refreshConfigurator, + this.onLoadAnimDuration, + this.loadVisible, + this.loadAnimDurationValue, + this.angle, + this.onLoadMore, + this.customLoad, + this.onAnimLoading, + this.mWidthNumber + ) + if (onLoadingValue !== undefined) { + this.loadAnimDurationValue = onLoadingValue.x; + this.onLoadAnimDuration = onLoadingValue.y; + this.angle =onLoadingValue.z ; + } + }, 7) + } + + private initCanvas(): void { + if (this.refreshRingOx == 0) { + if (this.canvasRefresh !== undefined && this.refreshConfigurator !== undefined) { + this.canvasRefresh.strokeStyle = this.refreshConfigurator.getRefreshColor() as string; + this.canvasRefresh.fillStyle = this.refreshConfigurator.getRefreshColor() as string; + this.canvasRefresh.lineWidth = this.refreshConfigurator.getRefreshHeight() / 120 + 1; + } + if (this.refreshConfigurator !== undefined) { + this.refreshRingOx = this.refreshConfigurator.getRefreshWidth() / 2; // 圆心x坐标 + this.refreshRingOy = this.refreshConfigurator.getRefreshHeight() / 2; // 圆心y坐标 + this.refreshRingRadius = this.refreshConfigurator.getRefreshHeight() / 8; // 半径 + this.refreshPoint1x = this.refreshRingOx + this.refreshRingRadius * Math.cos(Math.PI * 150 / 180); + this.refreshPoint1y = this.refreshRingOy + this.refreshRingRadius * Math.sin(Math.PI * 150 / 180); + this.refreshPoint2x = this.refreshRingOx + this.refreshRingRadius * Math.cos(Math.PI * -30 / 180); + this.refreshPoint2y = this.refreshRingOy + this.refreshRingRadius * Math.sin(Math.PI * -30 / 180); + } + } + } + + aboutToDisappear() { + clearInterval(this.timer); + } + + @Builder + refreshBuilder() { + Stack() { + if (this.customRefresh !== undefined && this.customRefresh !== null) { + Row() { + this.customRefresh(); + } + .visibility((this.refreshOffset > 0 && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) + } else { + Row() { + Stack() { + Text(this.refreshText) + .textAlign(TextAlign.Center) + .fontSize(this.refreshConfigurator?.getRefreshTextSize()) + .fontColor(this.refreshConfigurator?.getRefreshTextColor()) + Canvas(this.canvasRefresh) + .width('100%') + .height('100%') + .onReady(() => { + this.initCanvas(); + }) + .visibility(this.refreshState == RefreshStatus.Drag || this.refreshState == RefreshStatus.OverDrag ? Visibility.Visible : Visibility.Hidden) + LoadingProgress() + .width((this.refreshConfigurator?.getRefreshHeight() as number) / 2) + .height((this.refreshConfigurator?.getRefreshHeight() as number) / 2) + .color(this.refreshConfigurator?.getRefreshColor() as ResourceColor) + .visibility(this.refreshState == RefreshStatus.Refresh && !this.isShowRefreshText ? Visibility.Visible : Visibility.Hidden) + } + .width(this.refreshConfigurator?.getRefreshWidth()) + .height(this.refreshConfigurator?.getRefreshHeight()) + } + Image(this.refreshConfigurator?.getRefreshBackgroundImage()) + .opacity(this.refreshConfigurator?.getRefreshOpacity()) + } + } + .width('100%') + .align(Alignment.Center) + .visibility((this.refreshConfigurator?.getHasRefresh() && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) + } + + build() { + Refresh({ refreshing: $$this.refreshing, builder: this.refreshBuilder() }) { + if (this.pullToRefreshType === PullToRefreshType.LIST) { + ListComponent({ + modifier: this.modifierListAttribute, + refreshConfigurator: this.refreshConfigurator, + customList: this.customList, + customLoad: this.customLoad, + onLoadMore: this.onLoadMore, + mWidthNumber: this.mWidthNumber, + isTriggerPullUpLoading: this.isTriggerPullUpLoading, + angle: this.angle, + loadVisible: this.loadVisible + }) + } else if (this.pullToRefreshType === PullToRefreshType.SCROLL) { + ScrollComponent({ + modifier: this.modifierScrollAttribute, + refreshConfigurator: this.refreshConfigurator, + customList: this.customList, + customLoad: this.customLoad, + onLoadMore: this.onLoadMore, + mWidthNumber: this.mWidthNumber, + isTriggerPullUpLoading: this.isTriggerPullUpLoading, + angle: this.angle, + loadVisible: this.loadVisible + }) + } else if (this.pullToRefreshType === PullToRefreshType.GRID) { + GridComponent({ + modifier: this.modifierGridAttribute, + refreshConfigurator: this.refreshConfigurator, + customList: this.customList, + customLoad: this.customLoad, + onLoadMore: this.onLoadMore, + mWidthNumber: this.mWidthNumber, + isTriggerPullUpLoading: this.isTriggerPullUpLoading, + angle: this.angle, + layoutOptions: this.layoutOptions, + loadVisible: this.loadVisible, + data: this.data, + gridDataLength: this.gridDataLength + }) + } else { + WaterFlowComponent({ + modifier: this.modifierWaterFlowAttribute, + refreshConfigurator: this.refreshConfigurator, + customList: this.customList, + customLoad: this.customLoad, + onLoadMore: this.onLoadMore, + mWidthNumber: this.mWidthNumber, + isTriggerPullUpLoading: this.isTriggerPullUpLoading, + angle: this.angle, + loadVisible: this.loadVisible + }) + } + } + .width('100%') + .height('100%') + .onOffsetChange((value: number) => { + this.refreshOffset = value; + if ((this.refreshState == RefreshStatus.Drag || RefreshStatus.OverDrag) && + this.refreshConfigurator !== undefined) { + this.drawRefreshView(this.refreshOffset / this.refreshConfigurator.getRefreshHeight()) + } + }) + .refreshOffset(this.refreshConfigurator?.getRefreshHeight()) + .pullToRefresh(this.refreshConfigurator?.getHasRefresh()) + .backgroundColor(this.refreshConfigurator?.getHasRefresh() ? this.refreshConfigurator?.getRefreshBackgroundColor() : '') + .onStateChange((state: RefreshStatus) => { + this.refreshState = state; + if (state === RefreshStatus.Done) { + this.rangeValue = this.refreshConfigurator?.getRefreshHeight() as number; + } + }) + .onRefreshing(() => { + // 下拉刷新回调 + if (this.onRefresh !== undefined) { + this.onRefresh().then((refreshText: string) => { + if (refreshText.length > 0) { + this.showRefreshText(refreshText, 600); + } else { + this.hideRefreshText(); + } + }).catch((errorText: string) => { + this.showRefreshText(errorText, 800); + }) + } + }) + } + + private drawRefreshView(value: number): void { + if (this.refreshConfigurator !== undefined) { + let refreshHeightValue = this.refreshConfigurator.getRefreshHeight() + if (this.canvasRefresh !== undefined) { + let refreshWidth = this.refreshConfigurator.getRefreshWidth() + if (refreshWidth !== undefined) { + this.canvasRefresh.clearRect(0, 0, refreshWidth, refreshHeightValue); + } + // 绘制圆环 + this.canvasRefresh.beginPath(); + if (this.refreshRingOx !== undefined && this.refreshRingOy !== undefined && + this.refreshRingRadius !== undefined) { + this.canvasRefresh.arc(this.refreshRingOx, this.refreshRingOy, this.refreshRingRadius, 0, Math.PI * 2); + } + this.canvasRefresh.lineWidth = (this.refreshConfigurator.getRefreshHeight() / 2) / 60 + 1; + this.canvasRefresh.strokeStyle = this.refreshConfigurator.getRefreshColor() as string; + this.canvasRefresh.fillStyle = this.refreshConfigurator.getRefreshColor() as string; + this.canvasRefresh.stroke(); + // 绘制卫星 + value = value > 0.75 ? 0.75 : value; + this.canvasRefresh.beginPath(); + if (this.refreshPoint2x !== undefined && this.refreshPoint1x !== undefined + && this.refreshPoint2y !== undefined && this.refreshPoint1y !== undefined) { + this.canvasRefresh.arc( + value * (this.refreshPoint2x - this.refreshPoint1x) + this.refreshPoint1x, + value * (this.refreshPoint2y - this.refreshPoint1y) + this.refreshPoint1y, + refreshHeightValue / 2 / 20 + 1, 0, Math.PI * 2); + } + this.canvasRefresh.fill(); + } + } + } + + private showRefreshText(text: string, delay: number) { + this.isShowRefreshText = true; + this.refreshText = text; + let timer = setTimeout(() => { + this.refreshing = false; + this.isShowRefreshText = false; + this.refreshText = ''; + clearTimeout(timer); + }, delay) + } + + private hideRefreshText() { + this.refreshing = false; + this.isShowRefreshText = false; + this.refreshText = ''; + } +} + diff --git a/library/src/main/ets/components/PullToRefresh/PullToRefreshConfigurator.ets b/library/src/main/ets/components/PullToRefresh/PullToRefreshConfigurator.ets index ef06bebd07f2b2a96cee469c2ef25adf5bbc7644..c0963ac720964236c30479e5ffd25a426ae57636 100644 --- a/library/src/main/ets/components/PullToRefresh/PullToRefreshConfigurator.ets +++ b/library/src/main/ets/components/PullToRefresh/PullToRefreshConfigurator.ets @@ -21,7 +21,7 @@ export class PullToRefreshConfigurator { private loadBackgroundImage?: ResourceStr = ''; // 上拉加载动画部分的背景 private refreshOpacity?: number = 0.5; // 下拉刷新背景图的透明度 private loadOpacity?: number = 0.5; // 下拉刷新背景图的透明度 - private refreshColor?: ResourceColor | LinearGradient = ''; //下拉动画颜色 + private refreshColor?: ResourceColor | LinearGradient = '#999999'; //下拉动画颜色 private refreshBackgroundColor?: ResourceColor = 'rgba(0,0,0,0)'; // 下拉动画区域背景色 private refreshTextColor?: ResourceColor = '#999999'; // 下拉刷新提示文本的字体颜色 private refreshTextSize?: number | string | Resource = 16; // 下拉刷新提示文本的字体大小 diff --git a/library/src/main/ets/components/PullToRefresh/RefreshScroll.ets b/library/src/main/ets/components/PullToRefresh/ScrollComponent.ets similarity index 35% rename from library/src/main/ets/components/PullToRefresh/RefreshScroll.ets rename to library/src/main/ets/components/PullToRefresh/ScrollComponent.ets index feafe4d74d9d8aad719afbf3992adde1f237a91b..5c6f75faad288e1c61bb540abf4d710b5a4c9a0c 100644 --- a/library/src/main/ets/components/PullToRefresh/RefreshScroll.ets +++ b/library/src/main/ets/components/PullToRefresh/ScrollComponent.ets @@ -15,179 +15,34 @@ import { PullToRefreshConfigurator } from './PullToRefreshConfigurator'; @Component -export struct RefreshScroll { +export struct ScrollComponent { // 动态修改list组件的属性 modifier?: AttributeModifier; // 源数据 - @Link data: Object[]; - // 控制组件是否正在刷新 - @Link refreshing: boolean; - // 默认动画的value值 - @State refreshOffset: number = 0; - // 偏移距离 - private rangeValue: number = 64; + @Prop data: Object[]; // 刷新过程参数 @State refreshState: RefreshStatus = RefreshStatus.Inactive; // 是否触发上拉加载 - @State isTriggerPullUpLoading: boolean = false; + @Link isTriggerPullUpLoading: boolean; // 可滚动组件的控制器 private scroller: Scroller = new Scroller(); - // 回弹的回调 - onRefreshSpringBack?: (value?: number, height?: number) => void; // 组件属性配置 refreshConfigurator?: PullToRefreshConfigurator; // 上拉加载图片旋转参数 - @State private angle?: number | string = 0; + @Prop private angle?: number | string = 0; // 自定义组件主体布局 @BuilderParam customList?: () => void; - // 自定义下拉动画 - @BuilderParam customRefresh?: (() => void) | null; // 自定义上拉动画 @BuilderParam customLoad?: (() => void) | null; - // 下拉刷新回调 - onRefresh?: () => Promise = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve('刷新失败'); - }, 1000); - }); - }; // 上拉刷新回调 - onLoadMore?: () => Promise = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(''); - }, 1000); - }); - }; - // 开启自定义下拉动画 - onAnimPullDown?: (value?: number, width?: number, height?: number) => void; - onAnimRefreshing?: (value?: number, width?: number, height?: number) => void; - private refreshAnimDurationValue?: number = 0; - private mWidthNumber?: number = 0; - private timer?: number; - // 开启自定义上拉动画 - private loadAnimDurationValue?: number = 0; - private loadVisible?: Boolean = false; - private onLoadAnimDuration?: number = 0; - onAnimLoading?: (value?: number, width?: number, height?: number) => void; - - aboutToAppear() { - if (!this.refreshConfigurator) { - this.refreshConfigurator = new PullToRefreshConfigurator(); - } - this.timer = setInterval(() => { - //下拉阶段动画 - if (this.onAnimPullDown && (this.refreshState == RefreshStatus.Drag || this.refreshState == RefreshStatus.OverDrag && this.refreshConfigurator)) { - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - let value = this.refreshOffset > rangeHeightValue ? rangeHeightValue : this.refreshOffset; - this.onAnimPullDown(value / rangeHeightValue, this.mWidthNumber, this.refreshOffset) - } - //Refresh阶段动画 - if (this.refreshState == RefreshStatus.Refresh) { - let refreshAnimDuration = this.refreshConfigurator?.getRefreshAnimDuration(); - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - if (this.refreshAnimDurationValue !== undefined) { - if (this.refreshAnimDurationValue >= 1) { - this.refreshAnimDurationValue -= 1; - } else { - if (refreshAnimDuration !== undefined && refreshAnimDuration !== 0) { - this.refreshAnimDurationValue += 10 / refreshAnimDuration; - } - } - // 保留3位小数 - this.refreshAnimDurationValue = Math.round(this.refreshAnimDurationValue * 1000) / 1000; - } - // 如果又刷新中动画回调,就执行刷新中动画回调 - if (this.onAnimRefreshing) { - this.onAnimRefreshing(this.refreshAnimDurationValue, this.mWidthNumber, rangeHeightValue); - } - } - //Refresh结束回到顶部阶段 - if (this.refreshState == RefreshStatus.Done) { - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - if (this.rangeValue !== undefined && this.rangeValue > 0) { - this.rangeValue -= 5; - if (this.onRefreshSpringBack) { - this.onRefreshSpringBack(this.rangeValue, rangeHeightValue) - } - } - } - //上拉动画 - if (this.onLoadMore !== undefined && this.isTriggerPullUpLoading && this.loadVisible) { - //内置上拉动画 - if (this.loadAnimDurationValue !== undefined && !this.customLoad) { - if (this.loadAnimDurationValue >= 1) { - this.loadAnimDurationValue -= 1; - } else { - this.loadAnimDurationValue += 0.01; - } - // 保留2位小数 - this.loadAnimDurationValue = Math.round(this.loadAnimDurationValue * 100) / 100; - // 如果没有自定义加载中动画,就执行内置加载中动画 - this.angle = this.loadAnimDurationValue * 360; - } - //自定义上拉动画 - if (this.onLoadAnimDuration !== undefined && this.customLoad && this.onAnimLoading) { - let loadAnimDuration = this.refreshConfigurator?.getLoadAnimDuration(); - let loadHeightValue = this.refreshConfigurator?.getLoadImageHeight() as number; - if (this.onLoadAnimDuration >= 1) { - this.onLoadAnimDuration -= 1; - } else { - if (loadAnimDuration !== undefined && loadAnimDuration !== 0) { - this.onLoadAnimDuration += 10 / loadAnimDuration; - } - } - // 保留3位小数 - this.onLoadAnimDuration = Math.round(this.onLoadAnimDuration * 1000) / 1000; - this.onAnimLoading(this.onLoadAnimDuration, this.mWidthNumber, loadHeightValue); - } - } - }, 7) - } - - aboutToDisappear() { - clearInterval(this.timer); - } - @Builder - refreshBuilder() { - // 下拉刷新动画部分 - Stack({ alignContent: Alignment.Center }) { - if (this.customRefresh !== undefined && this.customRefresh !== null) { - Row(){ - this.customRefresh(); - } - .visibility((this.refreshOffset > 0 && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) - } else { - Row() { - Progress({ - value: this.refreshOffset, - total: this.refreshConfigurator?.getRefreshHeight(), - type: ProgressType.Ring - }) - .width(32) - .height(32) - .margin(10) - .color(this.refreshConfigurator?.getRefreshColor()) - .style({ - status: this.refreshing ? ProgressStatus.LOADING : ProgressStatus.PROGRESSING, - enableScanEffect: true - }) - Text('正在刷新...') - .fontSize(this.refreshConfigurator?.getRefreshTextSize()) - .margin({ left: 20 }) - .fontColor(this.refreshConfigurator?.getRefreshTextColor()) - } - Image(this.refreshConfigurator?.getRefreshBackgroundImage()) - .opacity(this.refreshConfigurator?.getRefreshOpacity()) - } - } - .width('100%') - .visibility((this.refreshConfigurator?.getHasRefresh() && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) - } + onLoadMore?: () => Promise; + // 组件的宽度 + @Link mWidthNumber: number; + // 是否显示上拉加载动画 + @Link loadVisible: Boolean; build() { - Refresh({ refreshing: $$this.refreshing, builder: this.refreshBuilder() }) { + Column(){ Scroll(this.scroller) { Column() { if (this.customList !== undefined) { @@ -212,7 +67,6 @@ export struct RefreshScroll { .width(30) .height(30) .margin({ right: 10 }) - Text(this.refreshConfigurator?.getLoadTextLoading()) .fontSize(this.refreshConfigurator?.getLoadTextSize()) .fontColor(this.refreshConfigurator?.getLoadTextColor()) @@ -225,7 +79,7 @@ export struct RefreshScroll { .height(this.refreshConfigurator?.getLoadImageHeight()) .visibility(this.isTriggerPullUpLoading ? Visibility.Visible : Visibility.None) .onVisibleAreaChange([0], (isVisible: boolean, currentRatio: number) => { - this.loadVisible = isVisible; + this.loadVisible = isVisible as boolean; if (isVisible && this.onLoadMore !== undefined) { isVisible && this.onLoading(); } @@ -248,28 +102,10 @@ export struct RefreshScroll { .attributeModifier(this.modifier) .onAreaChange((oldValue: Area, newValue: Area) => { this.mWidthNumber = Math.round(newValue.width as number); - this.refreshOffset = newValue.position.y as number; }) } .width('100%') .height('100%') - .refreshOffset(this.refreshConfigurator?.getRefreshHeight()) - .pullToRefresh(this.refreshConfigurator?.getHasRefresh()) - .backgroundColor(this.refreshConfigurator?.getHasRefresh() ? this.refreshConfigurator?.getRefreshBackgroundColor():'') - .onStateChange((state: RefreshStatus) => { - this.refreshState = state; - if (state == RefreshStatus.Done) { - this.rangeValue = this.refreshConfigurator?.getRefreshHeight() as number; - } - }) - .onRefreshing(() => { - // 下拉刷新回调 - if (this.onRefresh !== undefined) { - this.onRefresh().then((result) => { - this.refreshing = false; - }); - } - }) } private onLoading() { diff --git a/library/src/main/ets/components/PullToRefresh/RefreshWaterFlow.ets b/library/src/main/ets/components/PullToRefresh/WaterFlowComponent.ets similarity index 32% rename from library/src/main/ets/components/PullToRefresh/RefreshWaterFlow.ets rename to library/src/main/ets/components/PullToRefresh/WaterFlowComponent.ets index 1fd4b66c7072271a4839b140e66ddbc6fc786053..2b47ba8d546edf8d13cb4faecaca2375e65edba6 100644 --- a/library/src/main/ets/components/PullToRefresh/RefreshWaterFlow.ets +++ b/library/src/main/ets/components/PullToRefresh/WaterFlowComponent.ets @@ -15,177 +15,29 @@ import { PullToRefreshConfigurator } from './PullToRefreshConfigurator'; @Component -export struct RefreshWaterFlow { +export struct WaterFlowComponent { // 动态修改list组件的属性 modifier?: AttributeModifier; // 源数据 - @Link data: Object[]; - // 控制组件是否正在刷新 - @Link refreshing: boolean; - // 默认动画的value值 - @State refreshOffset: number = 0; - // 偏移距离 - private rangeValue: number = 64; - // 刷新过程参数 - @State refreshState: RefreshStatus = RefreshStatus.Inactive; + @Prop data: Object[]; // 是否触发上拉加载 - @State isTriggerPullUpLoading: boolean = false; + @Link isTriggerPullUpLoading: boolean ; // 可滚动组件的控制器 private scroller: Scroller = new Scroller(); - // 回弹的回调 - onRefreshSpringBack?: (value?: number, height?: number) => void; // 组件属性配置 refreshConfigurator?: PullToRefreshConfigurator; // 上拉加载图片旋转参数 - @State private angle?: number | string = 0; + @Prop private angle?: number | string = 0; // 自定义组件主体布局 @BuilderParam customList?: () => void; - // 自定义下拉动画 - @BuilderParam customRefresh?: (() => void) | null; // 自定义上拉动画 @BuilderParam customLoad?: (() => void) | null; - // 下拉刷新回调 - onRefresh?: () => Promise = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve('刷新失败'); - }, 1000); - }); - }; // 上拉刷新回调 - onLoadMore?: () => Promise = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(''); - }, 1000); - }); - }; - // 开启自定义下拉动画 - onAnimPullDown?: (value?: number, width?: number, height?: number) => void; - onAnimRefreshing?: (value?: number, width?: number, height?: number) => void; - private refreshAnimDurationValue?: number = 0; - private mWidthNumber?: number = 0; - private timer?: number; - // 开启自定义上拉动画 - private loadAnimDurationValue?: number = 0; - private loadVisible?: Boolean = false; - private onLoadAnimDuration?: number = 0; - onAnimLoading?: (value?: number, width?: number, height?: number) => void; - - aboutToAppear() { - if (!this.refreshConfigurator) { - this.refreshConfigurator = new PullToRefreshConfigurator(); - } - this.timer = setInterval(() => { - //下拉阶段动画 - if (this.onAnimPullDown && (this.refreshState == RefreshStatus.Drag || this.refreshState == RefreshStatus.OverDrag && this.refreshConfigurator)) { - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - let value = this.refreshOffset > rangeHeightValue ? rangeHeightValue : this.refreshOffset; - this.onAnimPullDown(value / rangeHeightValue, this.mWidthNumber, this.refreshOffset) - } - //Refresh阶段动画 - if (this.refreshState == RefreshStatus.Refresh) { - let refreshAnimDuration = this.refreshConfigurator?.getRefreshAnimDuration(); - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - if (this.refreshAnimDurationValue !== undefined) { - if (this.refreshAnimDurationValue >= 1) { - this.refreshAnimDurationValue -= 1; - } else { - if (refreshAnimDuration !== undefined && refreshAnimDuration !== 0) { - this.refreshAnimDurationValue += 10 / refreshAnimDuration; - } - } - // 保留3位小数 - this.refreshAnimDurationValue = Math.round(this.refreshAnimDurationValue * 1000) / 1000; - } - // 如果又刷新中动画回调,就执行刷新中动画回调 - if (this.onAnimRefreshing) { - this.onAnimRefreshing(this.refreshAnimDurationValue, this.mWidthNumber, rangeHeightValue); - } - } - //Refresh结束回到顶部阶段 - if (this.refreshState == RefreshStatus.Done) { - let rangeHeightValue = this.refreshConfigurator?.getRefreshHeight() as number; - if (this.rangeValue !== undefined && this.rangeValue > 0) { - this.rangeValue -= 5; - if (this.onRefreshSpringBack) { - this.onRefreshSpringBack(this.rangeValue, rangeHeightValue) - } - } - } - //上拉动画 - if (this.onLoadMore !== undefined && this.isTriggerPullUpLoading && this.loadVisible) { - //内置上拉动画 - if (this.loadAnimDurationValue !== undefined && !this.customLoad) { - if (this.loadAnimDurationValue >= 1) { - this.loadAnimDurationValue -= 1; - } else { - this.loadAnimDurationValue += 0.01; - } - // 保留2位小数 - this.loadAnimDurationValue = Math.round(this.loadAnimDurationValue * 100) / 100; - // 如果没有自定义加载中动画,就执行内置加载中动画 - this.angle = this.loadAnimDurationValue * 360; - } - //自定义上拉动画 - if (this.onLoadAnimDuration !== undefined && this.customLoad && this.onAnimLoading) { - let loadAnimDuration = this.refreshConfigurator?.getLoadAnimDuration(); - let loadHeightValue = this.refreshConfigurator?.getLoadImageHeight() as number; - if (this.onLoadAnimDuration >= 1) { - this.onLoadAnimDuration -= 1; - } else { - if (loadAnimDuration !== undefined && loadAnimDuration !== 0) { - this.onLoadAnimDuration += 10 / loadAnimDuration; - } - } - // 保留3位小数 - this.onLoadAnimDuration = Math.round(this.onLoadAnimDuration * 1000) / 1000; - this.onAnimLoading(this.onLoadAnimDuration, this.mWidthNumber, loadHeightValue); - } - } - }, 7) - } - - aboutToDisappear() { - clearInterval(this.timer); - } - @Builder - refreshBuilder() { - // 下拉刷新动画部分 - Stack({ alignContent: Alignment.Center }) { - if (this.customRefresh !== undefined && this.customRefresh !== null) { - Row(){ - this.customRefresh(); - } - .visibility((this.refreshOffset > 0 && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) - } else { - Row() { - Progress({ - value: this.refreshOffset, - total: this.refreshConfigurator?.getRefreshHeight(), - type: ProgressType.Ring - }) - .width(32) - .height(32) - .margin(10) - .color(this.refreshConfigurator?.getRefreshColor()) - .style({ - status: this.refreshing ? ProgressStatus.LOADING : ProgressStatus.PROGRESSING, - enableScanEffect: true - }) - Text('正在刷新...') - .fontSize(this.refreshConfigurator?.getRefreshTextSize()) - .margin({ left: 20 }) - .fontColor(this.refreshConfigurator?.getRefreshTextColor()) - } - - Image(this.refreshConfigurator?.getRefreshBackgroundImage()) - .opacity(this.refreshConfigurator?.getRefreshOpacity()) - } - } - .width('100%') - .visibility((this.refreshConfigurator?.getHasRefresh() && this.refreshState !== RefreshStatus.Inactive) ? Visibility.Visible : Visibility.None) - } + onLoadMore?: () => Promise; + //组件宽度 + @Link mWidthNumber: number; + //是否显示上拉加载 + @Link loadVisible: Boolean; @Builder flowFooter() { @@ -231,7 +83,7 @@ export struct RefreshWaterFlow { } build() { - Refresh({ refreshing: $$this.refreshing, builder: this.refreshBuilder() }) { + Column() { WaterFlow({ scroller: this.scroller, footer: this.flowFooter() }) { if (this.customList !== undefined) { this.customList(); @@ -248,28 +100,10 @@ export struct RefreshWaterFlow { .attributeModifier(this.modifier) .onAreaChange((oldValue: Area, newValue: Area) => { this.mWidthNumber = Math.round(newValue.width as number); - this.refreshOffset = newValue.position.y as number; }) } .width('100%') .height('100%') - .refreshOffset(this.refreshConfigurator?.getRefreshHeight()) - .pullToRefresh(this.refreshConfigurator?.getHasRefresh()) - .backgroundColor(this.refreshConfigurator?.getHasRefresh() ? this.refreshConfigurator?.getRefreshBackgroundColor():'') - .onStateChange((state: RefreshStatus) => { - this.refreshState = state; - if (state == RefreshStatus.Done) { - this.rangeValue = this.refreshConfigurator?.getRefreshHeight() as number; - } - }) - .onRefreshing(() => { - // 下拉刷新回调 - if (this.onRefresh !== undefined) { - this.onRefresh().then((result) => { - this.refreshing = false; - }); - } - }) } private onLoading() { diff --git a/library/src/main/ets/components/utils/PullToRefreshType.ets b/library/src/main/ets/components/utils/PullToRefreshType.ets new file mode 100644 index 0000000000000000000000000000000000000000..5c3b1cf0b4bef9cb6754f5f1161c542a4bc62d9d --- /dev/null +++ b/library/src/main/ets/components/utils/PullToRefreshType.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * 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. + */ + +export enum PullToRefreshType { + LIST, + SCROLL, + GRID, + WATERFLOW +} \ No newline at end of file diff --git a/library/src/main/ets/components/utils/RefreshStateUtil.ets b/library/src/main/ets/components/utils/RefreshStateUtil.ets new file mode 100644 index 0000000000000000000000000000000000000000..1dcde1e0e207b1e4a7ed50fba6cf49cd647b6808 --- /dev/null +++ b/library/src/main/ets/components/utils/RefreshStateUtil.ets @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * 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. + */ + +import { PullToRefreshConfigurator } from '../PullToRefresh/PullToRefreshConfigurator'; + +export class RefreshStateUtil { + static onAnimPullDownFun( + refreshOffset: number, refreshState: RefreshStatus, + onAnimPullDown?: Function, refreshConfigurator?: PullToRefreshConfigurator, + mWidthNumber?: number + ) { + if (onAnimPullDown && (refreshState == RefreshStatus.Drag || refreshState == RefreshStatus.OverDrag && refreshConfigurator)) { + let rangeHeightValue = refreshConfigurator?.getRefreshHeight() as number; + let value = refreshOffset > rangeHeightValue ? rangeHeightValue : refreshOffset; + onAnimPullDown(value / rangeHeightValue, mWidthNumber, refreshOffset) + } + } + + static onRefreshingFun( + refreshState: RefreshStatus, refreshConfigurator?: PullToRefreshConfigurator, + refreshAnimDurationValue?: number, mWidthNumber?: number, + onAnimRefreshing?: Function + ): allPullValue { + if (refreshState == RefreshStatus.Refresh) { + let refreshAnimDuration = refreshConfigurator?.getRefreshAnimDuration(); + let rangeHeightValue = refreshConfigurator?.getRefreshHeight() as number; + if (refreshAnimDurationValue !== undefined) { + if (refreshAnimDurationValue >= 1) { + refreshAnimDurationValue -= 1; + } else { + if (refreshAnimDuration !== undefined && refreshAnimDuration !== 0) { + refreshAnimDurationValue += 10 / refreshAnimDuration; + } + } + // 保留3位小数 + refreshAnimDurationValue = Math.round(refreshAnimDurationValue * 1000) / 1000; + } + // 如果又刷新中动画回调,就执行刷新中动画回调 + if (onAnimRefreshing) { + onAnimRefreshing(refreshAnimDurationValue, mWidthNumber, rangeHeightValue); + } + } + return { x: refreshAnimDurationValue } + } + + static onRefreshSpringBackFun( + rangeValue: number, refreshState: RefreshStatus, + refreshConfigurator?: PullToRefreshConfigurator, + onRefreshSpringBack?: Function + ): number { + if (refreshState == RefreshStatus.Done) { + let rangeHeightValue = refreshConfigurator?.getRefreshHeight() as number; + if (rangeValue !== undefined && rangeValue > 0) { + rangeValue -= 5; //注意这个地方应该用速度状态进行判断 + if (onRefreshSpringBack) { + onRefreshSpringBack(rangeValue, rangeHeightValue) + } + } + } + return rangeValue; + } + + static onAnimLoadingFun( + isTriggerPullUpLoading: boolean, refreshConfigurator?: PullToRefreshConfigurator, + onLoadAnimDuration?: number, loadVisible?: Boolean, + loadAnimDurationValue?: number, angle?: number | string, + onLoadMore?: Function, customLoad?: Function | null, + onAnimLoading?: Function, mWidthNumber?: number + ): allPullValue { + if (onLoadMore !== undefined && isTriggerPullUpLoading && loadVisible) { + //内置上拉动画 + if (loadAnimDurationValue !== undefined && !customLoad) { + if (loadAnimDurationValue >= 1) { + loadAnimDurationValue -= 1; + } else { + loadAnimDurationValue += 0.01; + } + // 保留2位小数 + loadAnimDurationValue = Math.round(loadAnimDurationValue * 100) / 100; + angle = loadAnimDurationValue * 360; + } + //自定义上拉动画 + if (onLoadAnimDuration !== undefined && customLoad && onAnimLoading) { + let loadAnimDuration = refreshConfigurator?.getLoadAnimDuration(); + let loadHeightValue = refreshConfigurator?.getLoadImageHeight() as number; + if (onLoadAnimDuration >= 1) { + onLoadAnimDuration -= 1; + } else { + if (loadAnimDuration !== undefined && loadAnimDuration !== 0) { + onLoadAnimDuration += 10 / loadAnimDuration; + } + } + // 保留3位小数 + onLoadAnimDuration = Math.round(onLoadAnimDuration * 1000) / 1000; + onAnimLoading(onLoadAnimDuration, mWidthNumber, loadHeightValue,angle); + } + } + return { x: loadAnimDurationValue, y: onLoadAnimDuration, z: angle } + } +} + +export interface allPullValue { + x?: number, + y?: number, + z?: number | string +}