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&lt;[DismissContentCoverAction](#dismisscontentcoveraction12)&gt; | 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![en-us_full_screen_modal_none_1](figures/en-us_full_screen_modal_none_1.gif)
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![en-us_full_screen_modal_none_2](figures/en-us_full_screen_modal_none_2.gif)
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![en-us_full_screen_modal_default](figures/en-us_full_screen_modal_default.gif)
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![en-us_full_screen_modal_alpha](figures/en-us_full_screen_modal_alpha.gif)
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![en-us_full_screen_modal_alpha](figures/en-us_full_screen_modal_transition.gif)
490