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).| 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-initiated attempt to close the modal.<br>**NOTE**<br>After this callback is registered, touching the Back button does not immediately close the modal. The **reason** parameter in the callback indicates the type of action that prevents the modal from being closed. You can specify whether to actually close the modal for the action. No more **onWillDismiss** callback is allowed in an **onWillDismiss** callback.<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 closed. Called when you need to exit the page.| 46| reason | [DismissReason](ts-universal-attributes-popup.md#dismissreason12) | Yes | Reason why the modal cannot be closed, that is, the type of action that prevents the modal from being closed. | 47 48## Example 49 50### Example 1 51 52This example applies a custom animation to two modals whose transition type is none. 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 myBuilder2() { 63 Column() { 64 Button("close modal 2") 65 .margin(10) 66 .fontSize(20) 67 .onClick(()=>{ 68 this.isShow2 = false; 69 }) 70 } 71 .width('100%') 72 .height('100%') 73 } 74 75 @Builder myBuilder() { 76 Column() { 77 Button("transition modal 2") 78 .margin(10) 79 .fontSize(20) 80 .onClick(()=>{ 81 this.isShow2 = true; 82 }).bindContentCover(this.isShow2, this.myBuilder2(), { 83 modalTransition: ModalTransition.NONE, 84 backgroundColor: Color.Orange, 85 onWillAppear: () => {console.log("BindContentCover onWillAppear.")}, 86 onAppear: () => {console.log("BindContentCover onAppear.")}, 87 onWillDisappear: () => {console.log("BindContentCover onWillDisappear.")}, 88 onDisappear: () => {console.log("BindContentCover onDisappear.")} 89 }) 90 91 Button("close modal 1") 92 .margin(10) 93 .fontSize(20) 94 .onClick(()=>{ 95 this.isShow = false; 96 }) 97 } 98 .width('100%') 99 .height('100%') 100 .justifyContent(FlexAlign.Center) 101 } 102 103 build() { 104 Column() { 105 Button("transition modal 1") 106 .onClick(() => { 107 this.isShow = true 108 }) 109 .fontSize(20) 110 .margin(10) 111 .bindContentCover(this.isShow, this.myBuilder(), { 112 modalTransition: ModalTransition.NONE, 113 backgroundColor: Color.Pink, 114 onWillAppear: () => {console.log("BindContentCover onWillAppear.")}, 115 onAppear: () => {console.log("BindContentCover onAppear.")}, 116 onWillDisappear: () => {console.log("BindContentCover onWillDisappear.")}, 117 onDisappear: () => {console.log("BindContentCover onDisappear.")} 118 }) 119 } 120 .justifyContent(FlexAlign.Center) 121 .backgroundColor("#ff49c8ab") 122 .width('100%') 123 .height('100%') 124 } 125} 126``` 127 128 129 130### Example 2 131 132This example applies a custom animation to two modals whose transition type is none. 133 134```ts 135// xxx.ets 136import { curves } from '@kit.ArkUI'; 137 138@Entry 139@Component 140struct ModalTransitionExample { 141 @State @Watch("isShow1Change") isShow:boolean = false 142 @State @Watch("isShow2Change") isShow2:boolean = false 143 @State isScale1:number = 1; 144 @State isScale2:number = 1; 145 146 isShow1Change() { 147 this.isShow ? this.isScale1 = 0.95 : this.isScale1 = 1 148 } 149 isShow2Change() { 150 this.isShow2 ? this.isScale2 = 0.95 : this.isScale2 = 1 151 } 152 @Builder myBuilder2() { 153 Column() { 154 Button("close modal 2") 155 .margin(10) 156 .fontSize(20) 157 .onClick(()=>{ 158 this.isShow2 = false; 159 }) 160 } 161 .width('100%') 162 .height('100%') 163 } 164 165 166 @Builder myBuilder() { 167 Column() { 168 Button("transition modal 2") 169 .margin(10) 170 .fontSize(20) 171 .onClick(()=>{ 172 this.isShow2 = true; 173 }).bindContentCover(this.isShow2, this.myBuilder2(), { 174 modalTransition: ModalTransition.NONE, 175 backgroundColor: Color.Orange, 176 onWillAppear: () => {console.log("BindContentCover onWillAppear.")}, 177 onAppear: () => {console.log("BindContentCover onAppear.")}, 178 onWillDisappear: () => {console.log("BindContentCover onWillDisappear.")}, 179 onDisappear: () => {console.log("BindContentCover onDisappear.")} 180 }) 181 182 Button("close modal 1") 183 .margin(10) 184 .fontSize(20) 185 .onClick(()=>{ 186 this.isShow = false; 187 }) 188 } 189 .width('100%') 190 .height('100%') 191 .justifyContent(FlexAlign.Center) 192 .scale({x: this.isScale2, y: this.isScale2}) 193 .animation({curve:curves.springMotion()}) 194 } 195 196 build() { 197 Column() { 198 Button("transition modal 1") 199 .onClick(() => { 200 this.isShow = true 201 }) 202 .fontSize(20) 203 .margin(10) 204 .bindContentCover(this.isShow, this.myBuilder(), { 205 modalTransition: ModalTransition.NONE, 206 backgroundColor: Color.Pink, 207 onWillAppear: () => {console.log("BindContentCover onWillAppear.")}, 208 onAppear: () => {console.log("BindContentCover onAppear.")}, 209 onWillDisappear: () => {console.log("BindContentCover onWillDisappear.")}, 210 onDisappear: () => {console.log("BindContentCover onDisappear.")} 211 }) 212 } 213 .justifyContent(FlexAlign.Center) 214 .backgroundColor("#ff49c8ab") 215 .width('100%') 216 .height('100%') 217 .scale({ x: this.isScale1, y: this.isScale1 }) 218 .animation({ curve: curves.springMotion() }) 219 } 220} 221``` 222 223 224 225### Example 3 226 227This example shows two modals whose transition type is slide-up and slide-down animation. 228 229```ts 230// xxx.ets 231@Entry 232@Component 233struct ModalTransitionExample { 234 @State isShow:boolean = false 235 @State isShow2:boolean = false 236 237 @Builder myBuilder2() { 238 Column() { 239 Button("close modal 2") 240 .margin(10) 241 .fontSize(20) 242 .onClick(()=>{ 243 this.isShow2 = false; 244 }) 245 } 246 .width('100%') 247 .height('100%') 248 } 249 250 @Builder myBuilder() { 251 Column() { 252 Button("transition modal 2") 253 .margin(10) 254 .fontSize(20) 255 .onClick(()=>{ 256 this.isShow2 = true; 257 }).bindContentCover(this.isShow2, this.myBuilder2(), { 258 modalTransition: ModalTransition.DEFAULT, 259 backgroundColor: Color.Gray, 260 onWillAppear: () => {console.log("BindContentCover onWillAppear.")}, 261 onAppear: () => {console.log("BindContentCover onAppear.")}, 262 onWillDisappear: () => {console.log("BindContentCover onWillDisappear.")}, 263 onDisappear: () => {console.log("BindContentCover onDisappear.")} 264 }) 265 266 Button("close modal 1") 267 .margin(10) 268 .fontSize(20) 269 .onClick(()=>{ 270 this.isShow = false; 271 }) 272 } 273 .width('100%') 274 .height('100%') 275 .justifyContent(FlexAlign.Center) 276 } 277 278 build() { 279 Column() { 280 Button("transition modal 1") 281 .onClick(() => { 282 this.isShow = true 283 }) 284 .fontSize(20) 285 .margin(10) 286 .bindContentCover(this.isShow, this.myBuilder(), { 287 modalTransition: ModalTransition.DEFAULT, 288 backgroundColor: Color.Pink, 289 onWillAppear: () => {console.log("BindContentCover onWillAppear.")}, 290 onAppear: () => {console.log("BindContentCover onAppear.")}, 291 onWillDisappear: () => {console.log("BindContentCover onWillDisappear.")}, 292 onDisappear: () => {console.log("BindContentCover onDisappear.")} 293 }) 294 } 295 .justifyContent(FlexAlign.Center) 296 .backgroundColor(Color.White) 297 .width('100%') 298 .height('100%') 299 } 300} 301``` 302 303 304 305### Example 4 306 307This example shows two modals whose transition type is opacity gradient animation. 308 309```ts 310// xxx.ets 311@Entry 312@Component 313struct ModalTransitionExample { 314 @State isShow:boolean = false 315 @State isShow2:boolean = false 316 317 @Builder myBuilder2() { 318 Column() { 319 Button("close modal 2") 320 .margin(10) 321 .fontSize(20) 322 .onClick(()=>{ 323 this.isShow2 = false; 324 }) 325 } 326 .width('100%') 327 .height('100%') 328 .justifyContent(FlexAlign.Center) 329 } 330 331 332 @Builder myBuilder() { 333 Column() { 334 Button("transition modal 2") 335 .margin(10) 336 .fontSize(20) 337 .onClick(()=>{ 338 this.isShow2 = true; 339 }).bindContentCover(this.isShow2, this.myBuilder2(), { 340 modalTransition: ModalTransition.ALPHA, 341 backgroundColor: Color.Gray, 342 onWillAppear: () => {console.log("BindContentCover onWillAppear.")}, 343 onAppear: () => {console.log("BindContentCover onAppear.")}, 344 onWillDisappear: () => {console.log("BindContentCover onWillDisappear.")}, 345 onDisappear: () => {console.log("BindContentCover onDisappear.")} 346 }) 347 348 Button("close modal 1") 349 .margin(10) 350 .fontSize(20) 351 .onClick(()=>{ 352 this.isShow = false; 353 }) 354 } 355 .width('100%') 356 .height('100%') 357 .justifyContent(FlexAlign.Center) 358 } 359 360 build() { 361 Column() { 362 Button("transition modal 1") 363 .onClick(() => { 364 this.isShow = true 365 }) 366 .fontSize(20) 367 .margin(10) 368 .bindContentCover(this.isShow, this.myBuilder(), { 369 modalTransition: ModalTransition.ALPHA, 370 backgroundColor: Color.Pink, 371 onWillAppear: () => {console.log("BindContentCover onWillAppear.")}, 372 onAppear: () => {console.log("BindContentCover onAppear.")}, 373 onWillDisappear: () => {console.log("BindContentCover onWillDisappear.")}, 374 onDisappear: () => {console.log("BindContentCover onDisappear.")} 375 }) 376 } 377 .justifyContent(FlexAlign.Center) 378 .backgroundColor(Color.White) 379 .width('100%') 380 .height('100%') 381 } 382} 383``` 384 385 386 387### Example 5 388 389This example shows a modal with a custom transition. 390 391```ts 392// xxx.ets 393@Entry 394@Component 395struct ModalTransitionExample { 396 @State isShow:boolean = false 397 @State isShow2:boolean = false 398 399 @Builder myBuilder2() { 400 Column() { 401 Button("Close Modal 2") 402 .margin(10) 403 .fontSize(20) 404 .onClick(()=>{ 405 this.isShow2 = false; 406 }) 407 } 408 .width('100%') 409 .height('100%') 410 .justifyContent(FlexAlign.Center) 411 } 412 413 @Builder myBuilder() { 414 Column() { 415 Button("Transition Modal 2") 416 .margin(10) 417 .fontSize(20) 418 .onClick(()=>{ 419 this.isShow2 = true; 420 }) 421 .bindContentCover( 422 this.isShow2, 423 this.myBuilder2(), 424 { 425 modalTransition: ModalTransition.DEFAULT, 426 backgroundColor: Color.Gray, 427 transition: TransitionEffect.SLIDE.animation({ duration: 5000, curve: Curve.LinearOutSlowIn }), 428 onWillDismiss: ((dismissContentCoverAction: DismissContentCoverAction) => { 429 if (dismissContentCoverAction.reason == DismissReason.PRESS_BACK) { 430 console.log("BindContentCover dismiss reason is back pressed") 431 } 432 dismissContentCoverAction.dismiss() 433 }), 434 onAppear: () => { console.info("BindContentCover onAppear.") }, 435 onDisappear: () => { this.isShow2 = false; console.info("BindContentCover onDisappear.") } 436 }) 437 438 Button("Close Modal 1") 439 .margin(10) 440 .fontSize(20) 441 .onClick(()=>{ 442 this.isShow = false; 443 }) 444 } 445 .width('100%') 446 .height('100%') 447 .justifyContent(FlexAlign.Center) 448 } 449 450 build() { 451 Column() { 452 Button("Transition Modal 1") 453 .onClick(() => { 454 this.isShow = true 455 }) 456 .fontSize(20) 457 .margin(10) 458 .bindContentCover( 459 this.isShow, 460 this.myBuilder(), 461 { 462 modalTransition: ModalTransition.DEFAULT, 463 backgroundColor: Color.Pink, 464 transition: TransitionEffect.asymmetric( 465 TransitionEffect.OPACITY.animation({ duration: 1100 }).combine( 466 TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ delay: 1000, duration: 1000 })) 467 , 468 TransitionEffect.OPACITY.animation({ duration: 1200 }).combine( 469 TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ duration: 1300 })) 470 ), 471 onWillDismiss: ((dismissContentCoverAction: DismissContentCoverAction) => { 472 if (dismissContentCoverAction.reason == DismissReason.PRESS_BACK) { 473 console.log("back pressed"); 474 } 475 dismissContentCoverAction.dismiss() 476 }), 477 onAppear: () => { console.log("BindContentCover onAppear.") }, 478 onDisappear: () => { this.isShow = false; console.log("BindContentCover onDisappear.") } 479 }) 480 } 481 .justifyContent(FlexAlign.Center) 482 .backgroundColor(Color.White) 483 .width('100%') 484 .height('100%') 485 } 486} 487``` 488 489 490