• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&lt;[DismissContentCoverAction](#dismisscontentcoveraction12类型说明)&gt; | 否 | 是   | 全屏模态页面交互式关闭回调函数。<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![zh-cn_full_screen_modal_none_1](figures/zh-cn_full_screen_modal_none_1.gif)
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![zh-cn_full_screen_modal_none_2](figures/zh-cn_full_screen_modal_none_2.gif)
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![zh-cn_full_screen_modal_default](figures/zh-cn_full_screen_modal_default.gif)
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![zh-cn_full_screen_modal_alpha](figures/zh-cn_full_screen_modal_alpha.gif)
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![zh-cn_full_screen_modal_alpha](figures/zh-cn_full_screen_modal_transition.gif)
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![zh-cn-enableSafeArea](figures/zh-cn-enablesafearea.png)