1# 全屏模态转场 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @CCFFWW--> 5<!--Designer: @yangfan229--> 6<!--Tester: @lxl007--> 7<!--Adviser: @HelloCrease--> 8 9通过bindContentCover属性为组件绑定全屏模态页面,在组件插入和移除时可通过设置转场参数ModalTransition显示过渡动效。 10 11> **说明:** 12> 13> 从API version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 14> 15> 不支持横竖屏切换。 16> 17> 不支持路由跳转。 18 19## bindContentCover 20 21bindContentCover(isShow: boolean, builder: CustomBuilder, options?: ContentCoverOptions): T 22 23给组件绑定全屏模态页面,点击后显示模态页面。模态页面内容自定义,显示方式可设置无动画过渡,上下切换过渡以及透明渐变过渡。 24 25**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 26 27**系统能力:** SystemCapability.ArkUI.ArkUI.Full 28 29**参数:** 30 31| 参数名 | 类型 | 必填 | 说明 | 32| ------- | ------------------------------------------- | ---- | ------------------------------------------------------------ | 33| isShow | boolean | 是 | 是否显示全屏模态页面。<br/>-true:显示全屏模态页面。<br/>-false:隐藏全屏模态页面。<br/>从API version 10开始,该参数支持[$$](../../../ui/state-management/arkts-two-way-sync.md)双向绑定变量。<br />从API version 18开始,该参数支持[!!](../../../ui/state-management/arkts-new-binding.md#系统组件参数双向绑定)双向绑定变量。| 34| builder | [CustomBuilder](ts-types.md#custombuilder8) | 是 | 配置全屏模态页面内容。 | 35| options | [ContentCoverOptions](#contentcoveroptions) | 否 | 配置全屏模态页面的可选属性。 | 36 37**返回值:** 38 39| 类型 | 说明 | 40| ------ | ------------------------ | 41| T | 返回当前组件。 | 42 43## ContentCoverOptions 44继承自[BindOptions](ts-universal-attributes-sheet-transition.md#bindoptions)。 45 46全屏模态页面内容选项。 47 48**系统能力:** SystemCapability.ArkUI.ArkUI.Full 49 50| 名称 | 类型 | 只读 | 可选 | 说明 | 51| --------------- | ---------------------------------------- | ---- | ---- | ------------- | 52| modalTransition | [ModalTransition](ts-universal-attributes-sheet-transition.md#modaltransition) | 否 | 是 | 全屏模态页面的系统转场方式。<br/> 默认值:ModalTransition.DEFAULT。<br/>**说明:**<br /> 同transition同时设置时,此属性不生效。<br />**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 | 53| onWillDismiss<sup>12+</sup> | Callback<[DismissContentCoverAction](#dismisscontentcoveraction12类型说明)> | 否 | 是 | 全屏模态页面交互式关闭回调函数。<br/>**说明:**<br />当用户执行back事件关闭交互操作时,如果注册该回调函数,则不会立刻关闭。在回调函数中可以通过reason得到阻拦关闭页面的操作类型,从而根据原因选择是否关闭全屏模态页面。在onWillDismiss回调中,不能再做onWillDismiss拦截。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。| 54| transition<sup>12+</sup> | [TransitionEffect](ts-transition-animation-component.md#transitioneffect10对象说明) | 否 | 是 | 全屏模态页面的自定义转场方式。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。| 55| enableSafeArea<sup>20+</sup> | boolean | 否 | 是 | 全屏模态是否适配安全区域,true表示全屏模态适配安全区域,将内容限制在安全区内,避让导航条和状态栏,false表示不做处理,和之前的样式保持一致。默认值为false。 <br />**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 | 56 57## DismissContentCoverAction<sup>12+</sup>类型说明 58 59**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 60 61**系统能力:** SystemCapability.ArkUI.ArkUI.Full 62 63| 名称 | 类型 | 只读 | 可选 | 说明 | 64| --------------- | -------------------- | -------------------- | ---- | ------------- | 65| dismiss | [Callback](./ts-types.md#callback12)\<void> | 否 | 否 | 全屏模态页面关闭回调函数。开发者需要退出页面时调用。 | 66| reason | [DismissReason](ts-universal-attributes-popup.md#dismissreason12枚举说明) | 否 | 否 | 返回本次拦截全屏模态页面退出的事件原因。 | 67 68## 示例 69 70### 示例1(使用全屏模态转场) 71 72该示例主要演示通过bindContentCover来实现全屏模态转场。 73 74```ts 75// xxx.ets 76@Entry 77@Component 78struct ModalTransitionExample { 79 @State isShow: boolean = false; 80 @State isShow2: boolean = false; 81 82 @Builder 83 myBuilder2() { 84 Column() { 85 Button("close modal 2") 86 .margin(10) 87 .fontSize(20) 88 .onClick(() => { 89 this.isShow2 = false; 90 }) 91 } 92 .width('100%') 93 .height('100%') 94 } 95 96 @Builder 97 myBuilder() { 98 Column() { 99 Button("transition modal 2") 100 .margin(10) 101 .fontSize(20) 102 .onClick(() => { 103 this.isShow2 = true; 104 }).bindContentCover(this.isShow2, this.myBuilder2(), { 105 modalTransition: ModalTransition.NONE, 106 backgroundColor: Color.Orange, 107 onWillAppear: () => { 108 console.log("BindContentCover onWillAppear."); 109 }, 110 onAppear: () => { 111 console.log("BindContentCover onAppear."); 112 }, 113 onWillDisappear: () => { 114 console.log("BindContentCover onWillDisappear."); 115 }, 116 onDisappear: () => { 117 console.log("BindContentCover onDisappear."); 118 } 119 }) 120 121 Button("close modal 1") 122 .margin(10) 123 .fontSize(20) 124 .onClick(() => { 125 this.isShow = false; 126 }) 127 } 128 .width('100%') 129 .height('100%') 130 .justifyContent(FlexAlign.Center) 131 } 132 133 build() { 134 Column() { 135 Button("transition modal 1") 136 .onClick(() => { 137 this.isShow = true; 138 }) 139 .fontSize(20) 140 .margin(10) 141 .bindContentCover(this.isShow, this.myBuilder(), { 142 modalTransition: ModalTransition.NONE, 143 backgroundColor: Color.Pink, 144 onWillAppear: () => { 145 console.log("BindContentCover onWillAppear."); 146 }, 147 onAppear: () => { 148 console.log("BindContentCover onAppear."); 149 }, 150 onWillDisappear: () => { 151 console.log("BindContentCover onWillDisappear."); 152 }, 153 onDisappear: () => { 154 console.log("BindContentCover onDisappear."); 155 } 156 }) 157 } 158 .justifyContent(FlexAlign.Center) 159 .backgroundColor("#ff49c8ab") 160 .width('100%') 161 .height('100%') 162 } 163} 164``` 165 166 167 168### 示例2(自定义转场动画) 169 170全屏模态无动画转场模式下,自定义转场动画。 171 172```ts 173// xxx.ets 174import { curves } from '@kit.ArkUI'; 175 176@Entry 177@Component 178struct ModalTransitionExample { 179 @State @Watch("isShow1Change") isShow: boolean = false; 180 @State @Watch("isShow2Change") isShow2: boolean = false; 181 @State isScale1: number = 1; 182 @State isScale2: number = 1; 183 184 isShow1Change() { 185 this.isShow ? this.isScale1 = 0.95 : this.isScale1 = 1; 186 } 187 188 isShow2Change() { 189 this.isShow2 ? this.isScale2 = 0.95 : this.isScale2 = 1; 190 } 191 192 @Builder 193 myBuilder2() { 194 Column() { 195 Button("close modal 2") 196 .margin(10) 197 .fontSize(20) 198 .onClick(() => { 199 this.isShow2 = false; 200 }) 201 } 202 .width('100%') 203 .height('100%') 204 } 205 206 @Builder 207 myBuilder() { 208 Column() { 209 Button("transition modal 2") 210 .margin(10) 211 .fontSize(20) 212 .onClick(() => { 213 this.isShow2 = true; 214 }).bindContentCover(this.isShow2, this.myBuilder2(), { 215 modalTransition: ModalTransition.NONE, 216 backgroundColor: Color.Orange, 217 onWillAppear: () => { 218 console.log("BindContentCover onWillAppear."); 219 }, 220 onAppear: () => { 221 console.log("BindContentCover onAppear."); 222 }, 223 onWillDisappear: () => { 224 console.log("BindContentCover onWillDisappear."); 225 }, 226 onDisappear: () => { 227 console.log("BindContentCover onDisappear."); 228 } 229 }) 230 231 Button("close modal 1") 232 .margin(10) 233 .fontSize(20) 234 .onClick(() => { 235 this.isShow = false; 236 }) 237 } 238 .width('100%') 239 .height('100%') 240 .justifyContent(FlexAlign.Center) 241 .scale({ x: this.isScale2, y: this.isScale2 }) 242 .animation({ curve: curves.springMotion() }) 243 } 244 245 build() { 246 Column() { 247 Button("transition modal 1") 248 .onClick(() => { 249 this.isShow = true; 250 }) 251 .fontSize(20) 252 .margin(10) 253 .bindContentCover(this.isShow, this.myBuilder(), { 254 modalTransition: ModalTransition.NONE, 255 backgroundColor: Color.Pink, 256 onWillAppear: () => { 257 console.log("BindContentCover onWillAppear."); 258 }, 259 onAppear: () => { 260 console.log("BindContentCover onAppear."); 261 }, 262 onWillDisappear: () => { 263 console.log("BindContentCover onWillDisappear."); 264 }, 265 onDisappear: () => { 266 console.log("BindContentCover onDisappear."); 267 } 268 }) 269 } 270 .justifyContent(FlexAlign.Center) 271 .backgroundColor("#ff49c8ab") 272 .width('100%') 273 .height('100%') 274 .scale({ x: this.isScale1, y: this.isScale1 }) 275 .animation({ curve: curves.springMotion() }) 276 } 277} 278``` 279 280 281 282### 示例3(上下切换转场) 283 284全屏模态上下切换转场。 285 286```ts 287// xxx.ets 288@Entry 289@Component 290struct ModalTransitionExample { 291 @State isShow: boolean = false; 292 @State isShow2: boolean = false; 293 294 @Builder 295 myBuilder2() { 296 Column() { 297 Button("close modal 2") 298 .margin(10) 299 .fontSize(20) 300 .onClick(() => { 301 this.isShow2 = false; 302 }) 303 } 304 .width('100%') 305 .height('100%') 306 } 307 308 @Builder 309 myBuilder() { 310 Column() { 311 Button("transition modal 2") 312 .margin(10) 313 .fontSize(20) 314 .onClick(() => { 315 this.isShow2 = true; 316 }).bindContentCover(this.isShow2, this.myBuilder2(), { 317 modalTransition: ModalTransition.DEFAULT, 318 backgroundColor: Color.Gray, 319 onWillAppear: () => { 320 console.log("BindContentCover onWillAppear."); 321 }, 322 onAppear: () => { 323 console.log("BindContentCover onAppear."); 324 }, 325 onWillDisappear: () => { 326 console.log("BindContentCover onWillDisappear."); 327 }, 328 onDisappear: () => { 329 console.log("BindContentCover onDisappear."); 330 } 331 }) 332 333 Button("close modal 1") 334 .margin(10) 335 .fontSize(20) 336 .onClick(() => { 337 this.isShow = false; 338 }) 339 } 340 .width('100%') 341 .height('100%') 342 .justifyContent(FlexAlign.Center) 343 } 344 345 build() { 346 Column() { 347 Button("transition modal 1") 348 .onClick(() => { 349 this.isShow = true; 350 }) 351 .fontSize(20) 352 .margin(10) 353 .bindContentCover(this.isShow, this.myBuilder(), { 354 modalTransition: ModalTransition.DEFAULT, 355 backgroundColor: Color.Pink, 356 onWillAppear: () => { 357 console.log("BindContentCover onWillAppear."); 358 }, 359 onAppear: () => { 360 console.log("BindContentCover onAppear."); 361 }, 362 onWillDisappear: () => { 363 console.log("BindContentCover onWillDisappear."); 364 }, 365 onDisappear: () => { 366 console.log("BindContentCover onDisappear."); 367 } 368 }) 369 } 370 .justifyContent(FlexAlign.Center) 371 .backgroundColor(Color.White) 372 .width('100%') 373 .height('100%') 374 } 375} 376``` 377 378 379 380### 示例4(透明度渐变转场) 381 382全屏模态透明度渐变转场。 383 384```ts 385// xxx.ets 386@Entry 387@Component 388struct ModalTransitionExample { 389 @State isShow: boolean = false; 390 @State isShow2: boolean = false; 391 392 @Builder 393 myBuilder2() { 394 Column() { 395 Button("close modal 2") 396 .margin(10) 397 .fontSize(20) 398 .onClick(() => { 399 this.isShow2 = false; 400 }) 401 } 402 .width('100%') 403 .height('100%') 404 .justifyContent(FlexAlign.Center) 405 } 406 407 @Builder 408 myBuilder() { 409 Column() { 410 Button("transition modal 2") 411 .margin(10) 412 .fontSize(20) 413 .onClick(() => { 414 this.isShow2 = true; 415 }).bindContentCover(this.isShow2, this.myBuilder2(), { 416 modalTransition: ModalTransition.ALPHA, 417 backgroundColor: Color.Gray, 418 onWillAppear: () => { 419 console.log("BindContentCover onWillAppear."); 420 }, 421 onAppear: () => { 422 console.log("BindContentCover onAppear."); 423 }, 424 onWillDisappear: () => { 425 console.log("BindContentCover onWillDisappear."); 426 }, 427 onDisappear: () => { 428 console.log("BindContentCover onDisappear."); 429 } 430 }) 431 432 Button("close modal 1") 433 .margin(10) 434 .fontSize(20) 435 .onClick(() => { 436 this.isShow = false; 437 }) 438 } 439 .width('100%') 440 .height('100%') 441 .justifyContent(FlexAlign.Center) 442 } 443 444 build() { 445 Column() { 446 Button("transition modal 1") 447 .onClick(() => { 448 this.isShow = true; 449 }) 450 .fontSize(20) 451 .margin(10) 452 .bindContentCover(this.isShow, this.myBuilder(), { 453 modalTransition: ModalTransition.ALPHA, 454 backgroundColor: Color.Pink, 455 onWillAppear: () => { 456 console.log("BindContentCover onWillAppear."); 457 }, 458 onAppear: () => { 459 console.log("BindContentCover onAppear."); 460 }, 461 onWillDisappear: () => { 462 console.log("BindContentCover onWillDisappear."); 463 }, 464 onDisappear: () => { 465 console.log("BindContentCover onDisappear."); 466 } 467 }) 468 } 469 .justifyContent(FlexAlign.Center) 470 .backgroundColor(Color.White) 471 .width('100%') 472 .height('100%') 473 } 474} 475``` 476 477 478 479### 示例5(设置不同效果的自定义转场) 480 481该示例主要演示全屏模态旋转,平移等自定义转场。 482 483```ts 484// xxx.ets 485@Entry 486@Component 487struct ModalTransitionExample { 488 @State isShow: boolean = false; 489 @State isShow2: boolean = false; 490 491 @Builder 492 myBuilder2() { 493 Column() { 494 Button("Close Modal 2") 495 .margin(10) 496 .fontSize(20) 497 .onClick(() => { 498 this.isShow2 = false; 499 }) 500 } 501 .width('100%') 502 .height('100%') 503 .justifyContent(FlexAlign.Center) 504 } 505 506 @Builder 507 myBuilder() { 508 Column() { 509 Button("Transition Modal 2") 510 .margin(10) 511 .fontSize(20) 512 .onClick(() => { 513 this.isShow2 = true; 514 }) 515 .bindContentCover( 516 this.isShow2, 517 this.myBuilder2(), 518 { 519 modalTransition: ModalTransition.DEFAULT, 520 backgroundColor: Color.Gray, 521 transition: TransitionEffect.SLIDE.animation({ duration: 5000, curve: Curve.LinearOutSlowIn }), 522 onWillDismiss: ((dismissContentCoverAction: DismissContentCoverAction) => { 523 if (dismissContentCoverAction.reason == DismissReason.PRESS_BACK) { 524 console.log("BindContentCover dismiss reason is back pressed"); 525 } 526 dismissContentCoverAction.dismiss(); 527 }), 528 onAppear: () => { 529 console.info("BindContentCover onAppear."); 530 }, 531 onDisappear: () => { 532 this.isShow2 = false; 533 console.info("BindContentCover onDisappear."); 534 } 535 }) 536 537 Button("Close Modal 1") 538 .margin(10) 539 .fontSize(20) 540 .onClick(() => { 541 this.isShow = false; 542 }) 543 } 544 .width('100%') 545 .height('100%') 546 .justifyContent(FlexAlign.Center) 547 } 548 549 build() { 550 Column() { 551 Button("Transition Modal 1") 552 .onClick(() => { 553 this.isShow = true; 554 }) 555 .fontSize(20) 556 .margin(10) 557 .bindContentCover( 558 this.isShow, 559 this.myBuilder(), 560 { 561 modalTransition: ModalTransition.DEFAULT, 562 backgroundColor: Color.Pink, 563 transition: TransitionEffect.asymmetric( 564 TransitionEffect.OPACITY.animation({ duration: 1100 }).combine( 565 TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ delay: 1000, duration: 1000 })) 566 , 567 TransitionEffect.OPACITY.animation({ duration: 1200 }).combine( 568 TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ duration: 1300 })) 569 ), 570 onWillDismiss: ((dismissContentCoverAction: DismissContentCoverAction) => { 571 if (dismissContentCoverAction.reason == DismissReason.PRESS_BACK) { 572 console.log("back pressed"); 573 } 574 dismissContentCoverAction.dismiss(); 575 }), 576 onAppear: () => { 577 console.log("BindContentCover onAppear."); 578 }, 579 onDisappear: () => { 580 this.isShow = false; 581 console.log("BindContentCover onDisappear."); 582 } 583 }) 584 } 585 .justifyContent(FlexAlign.Center) 586 .backgroundColor(Color.White) 587 .width('100%') 588 .height('100%') 589 } 590} 591``` 592 593 594 595### 示例6(设置全模态适配安全区) 596 597该示例主要演示通过设置enableSafeArea = true时,全模态适配安全区后,其内容效果。全模态容器其背景色为浅蓝色,内容颜色为灰色,内容在安全区内布局。 598 599```ts 600// xxx.ets 601@Entry 602@Component 603struct SafeAreaController { 604 @State isShow: boolean = false; 605 @State SafeArea: boolean | undefined = true; 606 @State heightMode: string = '100%'; 607 608 @Builder 609 myBuilder() { 610 Column() { 611 Column() { 612 Button("Content") 613 .fontSize(20) 614 } 615 .width('100%') 616 .height('50%') 617 .borderRadius(10) 618 .borderStyle(BorderStyle.Dotted) 619 .borderWidth(2) 620 Column() { 621 Button("Content") 622 .margin({top:340}) 623 .fontSize(20) 624 } 625 .width('100%') 626 .height('50%') 627 .borderRadius(10) 628 .borderStyle(BorderStyle.Dotted) 629 .borderWidth(2) 630 } 631 .backgroundColor(Color.Grey) 632 .justifyContent(FlexAlign.Center) 633 .width('100%') 634 .height(this.heightMode) 635 } 636 build() { 637 Column() { 638 Button("Open ContentCover") 639 .onClick(() => this.isShow = true) 640 .fontSize(20) 641 .margin(10) 642 .bindContentCover(this.isShow, this.myBuilder(), { 643 modalTransition: ModalTransition.ALPHA, 644 backgroundColor: 0x87CEEB, 645 // 动态设置安全区域模式 646 enableSafeArea: this.SafeArea 647 }) 648 } 649 .justifyContent(FlexAlign.Center) 650 .width('100%') 651 .height('100%') 652 } 653} 654``` 655 656