1# Refresh 2 3 可以进行页面下拉操作并显示刷新动效的容器组件。 4 5> **说明:** 6> 7> - 该组件从API Version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8> 9> - 该组件从API Version 12开始支持与垂直滚动的Swiper和Web的联动。当Swiper设置loop属性为true时,Refresh无法和Swiper产生联动。 10 11## 子组件 12 13支持单个子组件。 14 15从API version 11开始,Refresh子组件会跟随手势下拉而下移。 16 17## 接口 18 19Refresh(value: RefreshOptions) 20 21**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 22 23**系统能力:** SystemCapability.ArkUI.ArkUI.Full 24 25**参数:** 26 27| 参数名 | 类型 | 必填 | 说明 | 28| -------- | -------- | -------- | -------- | 29| value | [RefreshOptions](#refreshoptions对象说明)| 是 | 刷新组件参数。 | 30 31## RefreshOptions对象说明 32 33**系统能力:** SystemCapability.ArkUI.ArkUI.Full 34 35| 名称 | 类型 | 必填 | 说明 | 36| ---------- | ---------------------------------------- | ---- | ---------------------------------------- | 37| refreshing | boolean | 是 | 组件当前是否处于刷新中状态。true表示处于刷新中状态,false表示未处于刷新中状态。<br/>默认值:false<br/>该参数支持[$$](../../../quick-start/arkts-two-way-sync.md)双向绑定变量。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。| 38| offset<sup>(deprecated)</sup> | number \| string | 否 | 下拉起点距离组件顶部的距离。<br/>默认值:16,单位vp <br/>从API version 11开始废弃,无替代接口<br/>**说明:**<br/>offset取值范围[0vp,64vp]。大于64vp按照64vp处理。不支持百分比,不支持负数 。| 39| friction<sup>(deprecated)</sup> | number \| string | 否 | 下拉摩擦系数,取值范围为0到100。<br/>默认值:62<br/>- 0表示下拉刷新容器不跟随手势下拉而下拉。<br/>- 100表示下拉刷新容器紧紧跟随手势下拉而下拉。<br/>- 数值越大,下拉刷新容器跟随手势下拉的反应越灵敏。<br/>从API version 11开始废弃,从API version 12开始,可用[pullDownRatio](#pulldownratio12)属性替代。 | 40| builder<sup>10+</sup> | [CustomBuilder](ts-types.md#custombuilder8) | 否 | 自定义刷新区域显示内容。<br/>**说明:**<br/>API version 10及之前版本,自定义组件的高度限制在64vp之内。API version 11及以后版本没有此限制。 <br/>自定义组件设置了固定高度时,自定义组件会以固定高度显示在刷新区域下方;自定义组件未设置高度时,自定义组件高度会自适应刷新区域高度,会发生自定义组件高度跟随刷新区域变化至0的现象。建议对自定义组件设置最小高度约束来避免自定义组件高度小于预期的情况发生,具体可参照[示例3](#示例3自定义刷新区域显示内容-builder)。 <br/>从API version 12开始,建议使用refreshingContent参数替代builder参数自定义刷新区域显示内容,以避免刷新过程中因自定义组件销毁重建造成的动画中断问题。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。| 41| promptText<sup>12+</sup> | [ResourceStr](ts-types.md#resourcestr) | 否 | 设置刷新区域底部显示的自定义文本。<br/>**说明:**<br/>输入文本的限制参考Text组件,使用builder或refreshingContent参数自定义刷新区域显示内容时,promptText不显示。<br/>promptText设置有效时,[refreshOffset](#refreshoffset12)属性默认值为96vp。<br/>自定义文本最大的字体缩放倍数[maxFontScale](ts-basic-components-text.md#maxfontscale12)为2。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。| 42| refreshingContent<sup>12+</sup> | [ComponentContent](../js-apis-arkui-ComponentContent.md) | 否 | 自定义刷新区域显示内容。<br/>**说明:**<br/>与builder参数同时设置时builder参数不生效。<br/>自定义组件设置了固定高度时,自定义组件会以固定高度显示在刷新区域下方;自定义组件未设置高度时,自定义组件高度会自适应刷新区域高度,会发生自定义组件高度跟随刷新区域变化至0的现象。建议对自定义组件设置最小高度约束来避免自定义组件高度小于预期的情况发生,具体可参照[示例4](#示例4自定义刷新区域显示内容-refreshingcontent)。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。| 43 44> **补充说明:** 45> - 当未设置builder或refreshingContent时,是通过更新子组件的[translate](ts-universal-attributes-transformation.md#translate)属性实现的下拉位移效果,下拉位移过程中不会触发子组件的[onAreaChange](ts-universal-component-area-change-event.md#onareachange)事件,子组件设置[translate](ts-universal-attributes-transformation.md#translate)属性时不会生效。 46> - 当设置了builder或refreshingContent时,是通过更新子组件相对于Refresh组件的位置实现的下拉位移效果,下拉位移过程中可以触发子组件的[onAreaChange](ts-universal-component-area-change-event.md#onareachange)事件,子组件设置[position](ts-universal-attributes-location.md#position)属性时会固定子组件相对于Refresh组件的位置导致子组件不会跟手进行下拉位移。 47 48## 属性 49 50支持[通用属性](ts-universal-attributes-size.md)外,还支持以下属性: 51 52### refreshOffset<sup>12+</sup> 53 54refreshOffset(value: number) 55 56设置触发刷新的下拉偏移量,当下拉距离小于该属性设置值时离手不会触发刷新。 57 58**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 59 60**系统能力:** SystemCapability.ArkUI.ArkUI.Full 61 62**参数:** 63 64| 参数名 | 类型 | 必填 | 说明 | 65| ------ | ------------------------------------------- | ---- | ---------------------------------------------------------- | 66| value | number | 是 | 下拉偏移量,单位vp。<br/>默认值:未设置[promptText](#refreshoptions对象说明)参数时为64vp,设置了[promptText](#refreshoptions对象说明)参数时为96vp。 <br/>如果取值为0或负数的时候此接口采用默认值。| 67 68### pullToRefresh<sup>12+</sup> 69 70pullToRefresh(value: boolean) 71 72设置当下拉距离超过[refreshOffset](#refreshoffset12)时是否能触发刷新。 73 74**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 75 76**系统能力:** SystemCapability.ArkUI.ArkUI.Full 77 78**参数:** 79 80| 参数名 | 类型 | 必填 | 说明 | 81| ------ | ------------------------------------------- | ---- | ---------------------------------------------------------- | 82| value | boolean | 是 | 当下拉距离超过[refreshOffset](#refreshoffset12)时是否能触发刷新。true表示能触发刷新,false表示不能触发刷新。<br/>默认值:true | 83 84### pullDownRatio<sup>12+</sup> 85 86pullDownRatio(ratio: [Optional](ts-universal-attributes-custom-property.md#optional12)\<number>) 87 88设置下拉跟手系数。 89 90**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 91 92**系统能力:** SystemCapability.ArkUI.ArkUI.Full 93 94**参数:** 95 96| 参数名 | 类型 | 必填 | 说明 | 97| ------ | ------------------------------------------- | ---- | ---------------------------------------------------------- | 98| ratio | [Optional](ts-universal-attributes-custom-property.md#optional12)\<number> | 是 | 下拉跟手系数。数值越大,跟随手势下拉的反应越灵敏。0表示不跟随手势下拉,1表示等比例跟随手势下拉。<br/>没有设置或设置为undefined时,默认使用动态下拉跟手系数,下拉距离越大,跟手系数越小。<br/>有效值为0-1之间的值,小于0的值会被视为0,大于1的值会被视为1。 99 100## 事件 101 102除支持[通用事件](ts-universal-events-click.md)外,还支持以下事件: 103 104### onStateChange 105 106onStateChange(callback: (state: RefreshStatus) => void) 107 108当前刷新状态变更时,触发回调。 109 110**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 111 112**系统能力:** SystemCapability.ArkUI.ArkUI.Full 113 114**参数:** 115 116| 参数名 | 类型 | 必填 | 说明 | 117| ------ | --------------------------------------- | ---- | ---------- | 118| state | [RefreshStatus](#refreshstatus枚举说明) | 是 | 刷新状态。 | 119 120### onRefreshing 121 122onRefreshing(callback: () => void) 123 124进入刷新状态时触发回调。 125 126**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 127 128**系统能力:** SystemCapability.ArkUI.ArkUI.Full 129 130### onOffsetChange<sup>12+</sup> 131 132onOffsetChange(callback: Callback\<number>) 133 134下拉距离发生变化时触发回调。 135 136**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 137 138**系统能力:** SystemCapability.ArkUI.ArkUI.Full 139 140**参数:** 141 142| 参数名 | 类型 | 必填 | 说明 | 143| ------ | --------------------------------------- | ---- | ---------- | 144| callback | Callback\<number> | 是 | 下拉距离。<br/>单位:vp | 145 146 147## RefreshStatus枚举说明 148 149**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 150 151**系统能力:** SystemCapability.ArkUI.ArkUI.Full 152 153| 名称 | 值 | 说明 | 154| -------- | -------- | -------------------- | 155| Inactive | 0 | 默认未下拉状态。 | 156| Drag | 1 | 下拉中,下拉距离小于刷新距离。 | 157| OverDrag | 2 | 下拉中,下拉距离超过刷新距离。 | 158| Refresh | 3 | 下拉结束,回弹至刷新距离,进入刷新中状态。 | 159| Done | 4 | 刷新结束,返回初始状态(顶部)。 | 160 161 162## 示例 163 164### 示例1(默认刷新样式) 165 166刷新区域使用默认刷新样式。 167 168```ts 169// xxx.ets 170@Entry 171@Component 172struct RefreshExample { 173 @State isRefreshing: boolean = false 174 @State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] 175 176 build() { 177 Column() { 178 Refresh({ refreshing: $$this.isRefreshing }) { 179 List() { 180 ForEach(this.arr, (item: string) => { 181 ListItem() { 182 Text('' + item) 183 .width('70%') 184 .height(80) 185 .fontSize(16) 186 .margin(10) 187 .textAlign(TextAlign.Center) 188 .borderRadius(10) 189 .backgroundColor(0xFFFFFF) 190 } 191 }, (item: string) => item) 192 } 193 .onScrollIndex((first: number) => { 194 console.info(first.toString()) 195 }) 196 .width('100%') 197 .height('100%') 198 .alignListItem(ListItemAlign.Center) 199 .scrollBar(BarState.Off) 200 } 201 .onStateChange((refreshStatus: RefreshStatus) => { 202 console.info('Refresh onStatueChange state is ' + refreshStatus) 203 }) 204 .onOffsetChange((value: number) => { 205 console.info('Refresh onOffsetChange offset:' + value) 206 }) 207 .onRefreshing(() => { 208 setTimeout(() => { 209 this.isRefreshing = false 210 }, 2000) 211 console.log('onRefreshing test') 212 }) 213 .backgroundColor(0x89CFF0) 214 .refreshOffset(64) 215 .pullToRefresh(true) 216 } 217 } 218} 219``` 220 221 222 223### 示例2(设置刷新区域显示文本) 224 225通过[promptText](#refreshoptions对象说明)参数设置刷新区域显示文本。 226 227```ts 228// xxx.ets 229@Entry 230@Component 231struct RefreshExample { 232 @State isRefreshing: boolean = false 233 @State promptText: string = "Refreshing..." 234 @State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] 235 236 build() { 237 Column() { 238 Refresh({ refreshing: $$this.isRefreshing, promptText: this.promptText }) { 239 List() { 240 ForEach(this.arr, (item: string) => { 241 ListItem() { 242 Text('' + item) 243 .width('70%') 244 .height(80) 245 .fontSize(16) 246 .margin(10) 247 .textAlign(TextAlign.Center) 248 .borderRadius(10) 249 .backgroundColor(0xFFFFFF) 250 } 251 }, (item: string) => item) 252 } 253 .onScrollIndex((first: number) => { 254 console.info(first.toString()) 255 }) 256 .width('100%') 257 .height('100%') 258 .alignListItem(ListItemAlign.Center) 259 .scrollBar(BarState.Off) 260 } 261 .backgroundColor(0x89CFF0) 262 .pullToRefresh(true) 263 .refreshOffset(96) 264 .onStateChange((refreshStatus: RefreshStatus) => { 265 console.info('Refresh onStatueChange state is ' + refreshStatus) 266 }) 267 .onOffsetChange((value: number) => { 268 console.info('Refresh onOffsetChange offset:' + value) 269 }) 270 .onRefreshing(() => { 271 setTimeout(() => { 272 this.isRefreshing = false 273 }, 2000) 274 console.log('onRefreshing test') 275 }) 276 } 277 } 278} 279``` 280 281 282 283### 示例3(自定义刷新区域显示内容-builder) 284 285通过[builder](#refreshoptions对象说明)参数自定义刷新区域显示内容。 286 287```ts 288// xxx.ets 289@Entry 290@Component 291struct RefreshExample { 292 @State isRefreshing: boolean = false 293 @State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] 294 295 @Builder 296 customRefreshComponent() { 297 Stack() { 298 Row() { 299 LoadingProgress().height(32) 300 Text("Refreshing...").fontSize(16).margin({ left: 20 }) 301 } 302 .alignItems(VerticalAlign.Center) 303 } 304 .align(Alignment.Center) 305 .clip(true) 306 // 设置最小高度约束保证自定义组件高度随刷新区域高度变化时自定义组件高度不会低于minHeight 307 .constraintSize({ minHeight: 32 }) 308 .width("100%") 309 } 310 311 build() { 312 Column() { 313 Refresh({ refreshing: $$this.isRefreshing, builder: this.customRefreshComponent() }) { 314 List() { 315 ForEach(this.arr, (item: string) => { 316 ListItem() { 317 Text('' + item) 318 .width('70%') 319 .height(80) 320 .fontSize(16) 321 .margin(10) 322 .textAlign(TextAlign.Center) 323 .borderRadius(10) 324 .backgroundColor(0xFFFFFF) 325 } 326 }, (item: string) => item) 327 } 328 .onScrollIndex((first: number) => { 329 console.info(first.toString()) 330 }) 331 .width('100%') 332 .height('100%') 333 .alignListItem(ListItemAlign.Center) 334 .scrollBar(BarState.Off) 335 } 336 .backgroundColor(0x89CFF0) 337 .pullToRefresh(true) 338 .refreshOffset(64) 339 .onStateChange((refreshStatus: RefreshStatus) => { 340 console.info('Refresh onStatueChange state is ' + refreshStatus) 341 }) 342 .onRefreshing(() => { 343 setTimeout(() => { 344 this.isRefreshing = false 345 }, 2000) 346 console.log('onRefreshing test') 347 }) 348 } 349 } 350} 351``` 352 353 354 355### 示例4(自定义刷新区域显示内容-refreshingContent) 356 357通过[refreshingContent](#refreshoptions对象说明)参数自定义刷新区域显示内容。 358 359```ts 360// xxx.ets 361import { ComponentContent } from '@ohos.arkui.node'; 362 363class Params { 364 refreshStatus: RefreshStatus = RefreshStatus.Inactive 365 366 constructor(refreshStatus: RefreshStatus) { 367 this.refreshStatus = refreshStatus; 368 } 369} 370 371@Builder 372function customRefreshingContent(params: Params) { 373 Stack() { 374 Row() { 375 LoadingProgress().height(32) 376 Text("refreshStatus: " + params.refreshStatus).fontSize(16).margin({ left: 20 }) 377 } 378 .alignItems(VerticalAlign.Center) 379 } 380 .align(Alignment.Center) 381 .clip(true) 382 // 设置最小高度约束保证自定义组件高度随刷新区域高度变化时自定义组件高度不会低于minHeight 383 .constraintSize({ minHeight: 32 }) 384 .width("100%") 385} 386 387@Entry 388@Component 389struct RefreshExample { 390 @State isRefreshing: boolean = false 391 @State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] 392 @State refreshStatus: RefreshStatus = RefreshStatus.Inactive 393 private contentNode?: ComponentContent<Object> = undefined 394 private params: Params = new Params(RefreshStatus.Inactive) 395 396 aboutToAppear(): void { 397 let uiContext = this.getUIContext() 398 this.contentNode = new ComponentContent(uiContext, wrapBuilder(customRefreshingContent), this.params) 399 } 400 401 build() { 402 Column() { 403 Refresh({ refreshing: $$this.isRefreshing, refreshingContent: this.contentNode }) { 404 List() { 405 ForEach(this.arr, (item: string) => { 406 ListItem() { 407 Text('' + item) 408 .width('70%') 409 .height(80) 410 .fontSize(16) 411 .margin(10) 412 .textAlign(TextAlign.Center) 413 .borderRadius(10) 414 .backgroundColor(0xFFFFFF) 415 } 416 }, (item: string) => item) 417 } 418 .onScrollIndex((first: number) => { 419 console.info(first.toString()) 420 }) 421 .width('100%') 422 .height('100%') 423 .alignListItem(ListItemAlign.Center) 424 .scrollBar(BarState.Off) 425 } 426 .backgroundColor(0x89CFF0) 427 .pullToRefresh(true) 428 .refreshOffset(96) 429 .onStateChange((refreshStatus: RefreshStatus) => { 430 this.refreshStatus = refreshStatus 431 this.params.refreshStatus = refreshStatus 432 // 更新自定义组件内容 433 this.contentNode?.update(this.params) 434 console.info('Refresh onStatueChange state is ' + refreshStatus) 435 }) 436 .onRefreshing(() => { 437 setTimeout(() => { 438 this.isRefreshing = false 439 }, 2000) 440 console.log('onRefreshing test') 441 }) 442 } 443 } 444} 445``` 446 447 448### 示例5(实现最大下拉距离) 449 450通过[pullDownRatio](#pulldownratio12)属性和[onOffsetChange](#onoffsetchange12)事件实现最大下拉距离。 451 452```ts 453// xxx.ets 454import { ComponentContent } from '@ohos.arkui.node'; 455 456@Builder 457function customRefreshingContent() { 458 Stack() { 459 Row() { 460 LoadingProgress().height(32) 461 } 462 .alignItems(VerticalAlign.Center) 463 } 464 .align(Alignment.Center) 465 .clip(true) 466 // 设置最小高度约束保证自定义组件高度随刷新区域高度变化时自定义组件高度不会低于minHeight 467 .constraintSize({ minHeight: 32 }) 468 .width("100%") 469} 470 471@Entry 472@Component 473struct RefreshExample { 474 @State isRefreshing: boolean = false 475 @State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] 476 @State maxRefreshingHeight: number = 100.0 477 @State ratio: number = 1 478 private contentNode?: ComponentContent<Object> = undefined 479 480 aboutToAppear(): void { 481 let uiContext = this.getUIContext(); 482 this.contentNode = new ComponentContent(uiContext, wrapBuilder(customRefreshingContent)) 483 } 484 485 build() { 486 Column() { 487 Refresh({ refreshing: $$this.isRefreshing, refreshingContent: this.contentNode }) { 488 List() { 489 ForEach(this.arr, (item: string) => { 490 ListItem() { 491 Text('' + item) 492 .width('70%') 493 .height(80) 494 .fontSize(16) 495 .margin(10) 496 .textAlign(TextAlign.Center) 497 .borderRadius(10) 498 .backgroundColor(0xFFFFFF) 499 } 500 }, (item: string) => item) 501 } 502 .onScrollIndex((first: number) => { 503 console.info(first.toString()) 504 }) 505 .width('100%') 506 .height('100%') 507 .alignListItem(ListItemAlign.Center) 508 .scrollBar(BarState.Off) 509 } 510 .backgroundColor(0x89CFF0) 511 .pullDownRatio(this.ratio) 512 .pullToRefresh(true) 513 .refreshOffset(64) 514 .onOffsetChange((offset: number) => { 515 // 越接近最大距离,下拉跟手系数越小 516 this.ratio = 1 - Math.pow((offset / this.maxRefreshingHeight), 3) 517 }) 518 .onStateChange((refreshStatus: RefreshStatus) => { 519 console.info('Refresh onStatueChange state is ' + refreshStatus) 520 }) 521 .onRefreshing(() => { 522 setTimeout(() => { 523 this.isRefreshing = false 524 }, 2000) 525 console.log('onRefreshing test') 526 }) 527 } 528 } 529} 530``` 531 532 533 534### 示例6(实现下拉刷新上拉加载更多) 535 536[Refresh](#refresh)组件与[List](ts-container-list.md)组件组合实现下拉刷新上拉加载更多效果。 537 538```ts 539// xxx.ets 540@Entry 541@Component 542struct ListRefreshLoad { 543 @State arr: Array<number> = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 544 @State refreshing: boolean = false; 545 @State refreshOffset: number = 0; 546 @State refreshState: RefreshStatus = RefreshStatus.Inactive; 547 @State canLoad: boolean = false; 548 @State isLoading: boolean = false; 549 550 @Builder 551 refreshBuilder() { 552 Stack({ alignContent: Alignment.Bottom }) { 553 // 可以通过刷新状态控制是否存在Progress组件 554 // 当刷新状态处于下拉中或刷新中状态时Progress组件才存在 555 if (this.refreshState != RefreshStatus.Inactive && this.refreshState != RefreshStatus.Done) { 556 Progress({ value: this.refreshOffset, total: 64, type: ProgressType.Ring }) 557 .width(32).height(32) 558 .style({ status: this.refreshing ? ProgressStatus.LOADING : ProgressStatus.PROGRESSING }) 559 .margin(10) 560 } 561 } 562 .clip(true) 563 .height("100%") 564 .width("100%") 565 } 566 567 @Builder 568 footer() { 569 Row() { 570 LoadingProgress().height(32).width(48) 571 Text("加载中") 572 }.width("100%") 573 .height(64) 574 .justifyContent(FlexAlign.Center) 575 // 当不处于加载中状态时隐藏组件 576 .visibility(this.isLoading ? Visibility.Visible : Visibility.Hidden) 577 } 578 579 build() { 580 Refresh({ refreshing: $$this.refreshing, builder: this.refreshBuilder() }) { 581 List() { 582 ForEach(this.arr, (item: number) => { 583 ListItem() { 584 Text('' + item) 585 .width('100%') 586 .height(80) 587 .fontSize(16) 588 .textAlign(TextAlign.Center) 589 .backgroundColor(0xFFFFFF) 590 }.borderWidth(1) 591 }, (item: string) => item) 592 593 ListItem() { 594 this.footer(); 595 } 596 } 597 .onScrollIndex((start: number, end: number) => { 598 // 当达到列表末尾时,触发新数据加载 599 if (this.canLoad && end >= this.arr.length - 1) { 600 this.canLoad = false; 601 this.isLoading = true; 602 // 模拟新数据加载 603 setTimeout(() => { 604 for (let i = 0; i < 10; i++) { 605 this.arr.push(this.arr.length); 606 this.isLoading = false; 607 } 608 }, 700) 609 } 610 }) 611 .onScrollFrameBegin((offset: number, state: ScrollState) => { 612 // 只有当向上滑动时触发新数据加载 613 if (offset > 5 && !this.isLoading) { 614 this.canLoad = true; 615 } 616 return { offsetRemain: offset }; 617 }) 618 .scrollBar(BarState.Off) 619 // 开启边缘滑动效果 620 .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true }) 621 } 622 .width('100%') 623 .height('100%') 624 .backgroundColor(0xDCDCDC) 625 .onOffsetChange((offset: number) => { 626 this.refreshOffset = offset; 627 }) 628 .onStateChange((state: RefreshStatus) => { 629 this.refreshState = state; 630 }) 631 .onRefreshing(() => { 632 // 模拟数据刷新 633 setTimeout(() => { 634 this.refreshing = false; 635 }, 2000) 636 }) 637 } 638} 639``` 640 641