1# Modal Transition 2 3You can bind a full-screen modal to a component through the **bindContentCover** attribute. Better yet, with the **ModalTransition** parameter, you can apply a transition effect for when the component is inserted or deleted. 4 5> **NOTE** 6> 7> The APIs of this module are supported since API version 10. Updates will be marked with a superscript to indicate their earliest API version. 8> 9> Switching between landscape and portrait modes is not supported. 10> 11> Route hopping is not supported. 12 13## bindContentCover 14 15bindContentCover(isShow: Optional\<boolean\>, builder: CustomBuilder, options?: ContentCoverOptions) 16 17Binds a modal to the component, which can be displayed when the component is touched. The content of the modal is customizable. The transition type can be set to none, slide-up and slide-down animation, and opacity gradient animation. 18 19**Atomic service API**: This API can be used in atomic services since API version 11. 20 21**System capability**: SystemCapability.ArkUI.ArkUI.Full 22 23**Parameters** 24 25| Name | Type | Mandatory| Description | 26| ------- | ------------------------------------------- | ---- | ------------------------------------------------------------ | 27| isShow | Optional\<boolean\> | Yes | Whether to display the modal.<br>Since API version 10, this attribute supports two-way binding through [$$](../../../quick-start/arkts-two-way-sync.md).<br>Since API version 16, this parameter supports two-way binding through [!!](../../../quick-start/arkts-new-binding.md#two-way-binding-between-built-in-component-parameters).| 28| builder | [CustomBuilder](ts-types.md#custombuilder8) | Yes | Content of the modal. | 29| options | [ContentCoverOptions](#contentcoveroptions) | No | Optional attributes of the modal. | 30 31## ContentCoverOptions 32Inherited from [BindOptions](ts-universal-attributes-sheet-transition.md#bindoptions). 33| Name | Type | Mandatory | Description | 34| --------------- | ---------------------------------------- | ---- | ------------- | 35| modalTransition | [ModalTransition](ts-types.md#modaltransition10) | No | Transition mode of the modal.<br>**Atomic service API**: This API can be used in atomic services since API version 11. | 36| onWillDismiss<sup>12+</sup> | Callback<[DismissContentCoverAction](#dismisscontentcoveraction12)> | No | Callback invoked to prevent a user attempt to dismiss the modal.<br>**NOTE**<br>After this callback is registered, touching the back button does not immediately dismiss the modal. You can use the **reason** parameter to determine the type of operation that triggers the dismissal and decide whether to dismiss the modal based on the reason. Nesting **onWillDismiss** callbacks is not allowed.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 37| transition<sup>12+</sup> | [TransitionEffect](ts-transition-animation-component.md#transitioneffect10) | No | Transition mode of the modal.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 38 39## DismissContentCoverAction<sup>12+</sup> 40 41**Atomic service API**: This API can be used in atomic services since API version 12. 42 43| Name | Type | Mandatory | Description | 44| --------------- | ---------------------------------------- | ---- | ------------- | 45| dismiss | function | Yes | Callback invoked when the modal is dismissed. Called when you need to exit the page.| 46| reason | [DismissReason](ts-universal-attributes-popup.md#dismissreason12) | Yes | Type of operation that triggers the dismissal of the modal. | 47 48## Example 49 50### Example 1: Implementing Modal Transition Using bindContentCover 51 52This example demonstrates how to implement a modal transition using the **bindContentCover** API. 53 54```ts 55// xxx.ets 56@Entry 57@Component 58struct ModalTransitionExample { 59 @State isShow: boolean = false 60 @State isShow2: boolean = false 61 62 @Builder 63 myBuilder2() { 64 Column() { 65 Button("close modal 2") 66 .margin(10) 67 .fontSize(20) 68 .onClick(() => { 69 this.isShow2 = false; 70 }) 71 } 72 .width('100%') 73 .height('100%') 74 } 75 76 @Builder 77 myBuilder() { 78 Column() { 79 Button("transition modal 2") 80 .margin(10) 81 .fontSize(20) 82 .onClick(() => { 83 this.isShow2 = true; 84 }).bindContentCover(this.isShow2, this.myBuilder2(), { 85 modalTransition: ModalTransition.NONE, 86 backgroundColor: Color.Orange, 87 onWillAppear: () => { 88 console.log("BindContentCover onWillAppear.") 89 }, 90 onAppear: () => { 91 console.log("BindContentCover onAppear.") 92 }, 93 onWillDisappear: () => { 94 console.log("BindContentCover onWillDisappear.") 95 }, 96 onDisappear: () => { 97 console.log("BindContentCover onDisappear.") 98 } 99 }) 100 101 Button("close modal 1") 102 .margin(10) 103 .fontSize(20) 104 .onClick(() => { 105 this.isShow = false; 106 }) 107 } 108 .width('100%') 109 .height('100%') 110 .justifyContent(FlexAlign.Center) 111 } 112 113 build() { 114 Column() { 115 Button("transition modal 1") 116 .onClick(() => { 117 this.isShow = true 118 }) 119 .fontSize(20) 120 .margin(10) 121 .bindContentCover(this.isShow, this.myBuilder(), { 122 modalTransition: ModalTransition.NONE, 123 backgroundColor: Color.Pink, 124 onWillAppear: () => { 125 console.log("BindContentCover onWillAppear.") 126 }, 127 onAppear: () => { 128 console.log("BindContentCover onAppear.") 129 }, 130 onWillDisappear: () => { 131 console.log("BindContentCover onWillDisappear.") 132 }, 133 onDisappear: () => { 134 console.log("BindContentCover onDisappear.") 135 } 136 }) 137 } 138 .justifyContent(FlexAlign.Center) 139 .backgroundColor("#ff49c8ab") 140 .width('100%') 141 .height('100%') 142 } 143} 144``` 145 146 147 148### Example 2: Implementing a Custom Transition Animation 149 150This example applies a custom animation to two modals whose transition type is none. 151 152```ts 153// xxx.ets 154import { curves } from '@kit.ArkUI'; 155 156@Entry 157@Component 158struct ModalTransitionExample { 159 @State @Watch("isShow1Change") isShow: boolean = false 160 @State @Watch("isShow2Change") isShow2: boolean = false 161 @State isScale1: number = 1; 162 @State isScale2: number = 1; 163 164 isShow1Change() { 165 this.isShow ? this.isScale1 = 0.95 : this.isScale1 = 1 166 } 167 168 isShow2Change() { 169 this.isShow2 ? this.isScale2 = 0.95 : this.isScale2 = 1 170 } 171 172 @Builder 173 myBuilder2() { 174 Column() { 175 Button("close modal 2") 176 .margin(10) 177 .fontSize(20) 178 .onClick(() => { 179 this.isShow2 = false; 180 }) 181 } 182 .width('100%') 183 .height('100%') 184 } 185 186 @Builder 187 myBuilder() { 188 Column() { 189 Button("transition modal 2") 190 .margin(10) 191 .fontSize(20) 192 .onClick(() => { 193 this.isShow2 = true; 194 }).bindContentCover(this.isShow2, this.myBuilder2(), { 195 modalTransition: ModalTransition.NONE, 196 backgroundColor: Color.Orange, 197 onWillAppear: () => { 198 console.log("BindContentCover onWillAppear.") 199 }, 200 onAppear: () => { 201 console.log("BindContentCover onAppear.") 202 }, 203 onWillDisappear: () => { 204 console.log("BindContentCover onWillDisappear.") 205 }, 206 onDisappear: () => { 207 console.log("BindContentCover onDisappear.") 208 } 209 }) 210 211 Button("close modal 1") 212 .margin(10) 213 .fontSize(20) 214 .onClick(() => { 215 this.isShow = false; 216 }) 217 } 218 .width('100%') 219 .height('100%') 220 .justifyContent(FlexAlign.Center) 221 .scale({ x: this.isScale2, y: this.isScale2 }) 222 .animation({ curve: curves.springMotion() }) 223 } 224 225 build() { 226 Column() { 227 Button("transition modal 1") 228 .onClick(() => { 229 this.isShow = true 230 }) 231 .fontSize(20) 232 .margin(10) 233 .bindContentCover(this.isShow, this.myBuilder(), { 234 modalTransition: ModalTransition.NONE, 235 backgroundColor: Color.Pink, 236 onWillAppear: () => { 237 console.log("BindContentCover onWillAppear.") 238 }, 239 onAppear: () => { 240 console.log("BindContentCover onAppear.") 241 }, 242 onWillDisappear: () => { 243 console.log("BindContentCover onWillDisappear.") 244 }, 245 onDisappear: () => { 246 console.log("BindContentCover onDisappear.") 247 } 248 }) 249 } 250 .justifyContent(FlexAlign.Center) 251 .backgroundColor("#ff49c8ab") 252 .width('100%') 253 .height('100%') 254 .scale({ x: this.isScale1, y: this.isScale1 }) 255 .animation({ curve: curves.springMotion() }) 256 } 257} 258``` 259 260 261 262### Example 3: Implementing a Slide-up and Slide-down Transition Animation 263 264This example shows two modals whose transition type is slide-up and slide-down animation. 265 266```ts 267// xxx.ets 268@Entry 269@Component 270struct ModalTransitionExample { 271 @State isShow: boolean = false 272 @State isShow2: boolean = false 273 274 @Builder 275 myBuilder2() { 276 Column() { 277 Button("close modal 2") 278 .margin(10) 279 .fontSize(20) 280 .onClick(() => { 281 this.isShow2 = false; 282 }) 283 } 284 .width('100%') 285 .height('100%') 286 } 287 288 @Builder 289 myBuilder() { 290 Column() { 291 Button("transition modal 2") 292 .margin(10) 293 .fontSize(20) 294 .onClick(() => { 295 this.isShow2 = true; 296 }).bindContentCover(this.isShow2, this.myBuilder2(), { 297 modalTransition: ModalTransition.DEFAULT, 298 backgroundColor: Color.Gray, 299 onWillAppear: () => { 300 console.log("BindContentCover onWillAppear.") 301 }, 302 onAppear: () => { 303 console.log("BindContentCover onAppear.") 304 }, 305 onWillDisappear: () => { 306 console.log("BindContentCover onWillDisappear.") 307 }, 308 onDisappear: () => { 309 console.log("BindContentCover onDisappear.") 310 } 311 }) 312 313 Button("close modal 1") 314 .margin(10) 315 .fontSize(20) 316 .onClick(() => { 317 this.isShow = false; 318 }) 319 } 320 .width('100%') 321 .height('100%') 322 .justifyContent(FlexAlign.Center) 323 } 324 325 build() { 326 Column() { 327 Button("transition modal 1") 328 .onClick(() => { 329 this.isShow = true 330 }) 331 .fontSize(20) 332 .margin(10) 333 .bindContentCover(this.isShow, this.myBuilder(), { 334 modalTransition: ModalTransition.DEFAULT, 335 backgroundColor: Color.Pink, 336 onWillAppear: () => { 337 console.log("BindContentCover onWillAppear.") 338 }, 339 onAppear: () => { 340 console.log("BindContentCover onAppear.") 341 }, 342 onWillDisappear: () => { 343 console.log("BindContentCover onWillDisappear.") 344 }, 345 onDisappear: () => { 346 console.log("BindContentCover onDisappear.") 347 } 348 }) 349 } 350 .justifyContent(FlexAlign.Center) 351 .backgroundColor(Color.White) 352 .width('100%') 353 .height('100%') 354 } 355} 356``` 357 358 359 360### Example 4: Implementing an Opacity Transition Animation 361 362This example shows two modals whose transition type is opacity animation. 363 364```ts 365// xxx.ets 366@Entry 367@Component 368struct ModalTransitionExample { 369 @State isShow: boolean = false 370 @State isShow2: boolean = false 371 372 @Builder 373 myBuilder2() { 374 Column() { 375 Button("close modal 2") 376 .margin(10) 377 .fontSize(20) 378 .onClick(() => { 379 this.isShow2 = false; 380 }) 381 } 382 .width('100%') 383 .height('100%') 384 .justifyContent(FlexAlign.Center) 385 } 386 387 @Builder 388 myBuilder() { 389 Column() { 390 Button("transition modal 2") 391 .margin(10) 392 .fontSize(20) 393 .onClick(() => { 394 this.isShow2 = true; 395 }).bindContentCover(this.isShow2, this.myBuilder2(), { 396 modalTransition: ModalTransition.ALPHA, 397 backgroundColor: Color.Gray, 398 onWillAppear: () => { 399 console.log("BindContentCover onWillAppear.") 400 }, 401 onAppear: () => { 402 console.log("BindContentCover onAppear.") 403 }, 404 onWillDisappear: () => { 405 console.log("BindContentCover onWillDisappear.") 406 }, 407 onDisappear: () => { 408 console.log("BindContentCover onDisappear.") 409 } 410 }) 411 412 Button("close modal 1") 413 .margin(10) 414 .fontSize(20) 415 .onClick(() => { 416 this.isShow = false; 417 }) 418 } 419 .width('100%') 420 .height('100%') 421 .justifyContent(FlexAlign.Center) 422 } 423 424 build() { 425 Column() { 426 Button("transition modal 1") 427 .onClick(() => { 428 this.isShow = true 429 }) 430 .fontSize(20) 431 .margin(10) 432 .bindContentCover(this.isShow, this.myBuilder(), { 433 modalTransition: ModalTransition.ALPHA, 434 backgroundColor: Color.Pink, 435 onWillAppear: () => { 436 console.log("BindContentCover onWillAppear.") 437 }, 438 onAppear: () => { 439 console.log("BindContentCover onAppear.") 440 }, 441 onWillDisappear: () => { 442 console.log("BindContentCover onWillDisappear.") 443 }, 444 onDisappear: () => { 445 console.log("BindContentCover onDisappear.") 446 } 447 }) 448 } 449 .justifyContent(FlexAlign.Center) 450 .backgroundColor(Color.White) 451 .width('100%') 452 .height('100%') 453 } 454} 455``` 456 457 458 459### Example 5: Implementing Custom Transitions with Different Effects 460 461This example demonstrates custom transitions for modals, including rotation and translation effects. 462 463```ts 464// xxx.ets 465@Entry 466@Component 467struct ModalTransitionExample { 468 @State isShow: boolean = false 469 @State isShow2: boolean = false 470 471 @Builder 472 myBuilder2() { 473 Column() { 474 Button("Close Modal 2") 475 .margin(10) 476 .fontSize(20) 477 .onClick(() => { 478 this.isShow2 = false; 479 }) 480 } 481 .width('100%') 482 .height('100%') 483 .justifyContent(FlexAlign.Center) 484 } 485 486 @Builder 487 myBuilder() { 488 Column() { 489 Button("Transition Modal 2") 490 .margin(10) 491 .fontSize(20) 492 .onClick(() => { 493 this.isShow2 = true; 494 }) 495 .bindContentCover( 496 this.isShow2, 497 this.myBuilder2(), 498 { 499 modalTransition: ModalTransition.DEFAULT, 500 backgroundColor: Color.Gray, 501 transition: TransitionEffect.SLIDE.animation({ duration: 5000, curve: Curve.LinearOutSlowIn }), 502 onWillDismiss: ((dismissContentCoverAction: DismissContentCoverAction) => { 503 if (dismissContentCoverAction.reason == DismissReason.PRESS_BACK) { 504 console.log("BindContentCover dismiss reason is back pressed") 505 } 506 dismissContentCoverAction.dismiss() 507 }), 508 onAppear: () => { 509 console.info("BindContentCover onAppear.") 510 }, 511 onDisappear: () => { 512 this.isShow2 = false; 513 console.info("BindContentCover onDisappear.") 514 } 515 }) 516 517 Button("Close Modal 1") 518 .margin(10) 519 .fontSize(20) 520 .onClick(() => { 521 this.isShow = false; 522 }) 523 } 524 .width('100%') 525 .height('100%') 526 .justifyContent(FlexAlign.Center) 527 } 528 529 build() { 530 Column() { 531 Button("Transition Modal 1") 532 .onClick(() => { 533 this.isShow = true 534 }) 535 .fontSize(20) 536 .margin(10) 537 .bindContentCover( 538 this.isShow, 539 this.myBuilder(), 540 { 541 modalTransition: ModalTransition.DEFAULT, 542 backgroundColor: Color.Pink, 543 transition: TransitionEffect.asymmetric( 544 TransitionEffect.OPACITY.animation({ duration: 1100 }).combine( 545 TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ delay: 1000, duration: 1000 })) 546 , 547 TransitionEffect.OPACITY.animation({ duration: 1200 }).combine( 548 TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ duration: 1300 })) 549 ), 550 onWillDismiss: ((dismissContentCoverAction: DismissContentCoverAction) => { 551 if (dismissContentCoverAction.reason == DismissReason.PRESS_BACK) { 552 console.log("back pressed"); 553 } 554 dismissContentCoverAction.dismiss() 555 }), 556 onAppear: () => { 557 console.log("BindContentCover onAppear.") 558 }, 559 onDisappear: () => { 560 this.isShow = false; 561 console.log("BindContentCover onDisappear.") 562 } 563 }) 564 } 565 .justifyContent(FlexAlign.Center) 566 .backgroundColor(Color.White) 567 .width('100%') 568 .height('100%') 569 } 570} 571``` 572 573 574