• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Basic Custom Dialog Box (CustomDialog) (Not Recommended)
2A custom dialog box is a dialog box you customize by using APIs of the **CustomDialogController** class. It can be used for user interactions, showing ads, award announcements, alerts, software update notifications, and more. For details, see [Custom Dialog Box](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md).
3
4> **NOTE**
5>
6> In ArkUI, dialog boxes do not close automatically when you switch pages unless you manually call **close**. To enable a dialog box to be dismissed during page navigation, consider using the [navigation page displayed in dialog mode](arkts-navigation-navigation.md#page-display-mode) or [page-level dialog box](arkts-embedded-dialog.md).
7
8You can specify the modality of a dialog box by setting [isModal](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md#customdialogcontrolleroptions). A dialog box is modal if **isModal** is set to **true** and non-modal otherwise.
9
10## Creating a Custom Dialog Box
11
121. Use the \@CustomDialog decorator to create a custom dialog box. You can define the content of the dialog box within the decorator. Note that **CustomDialogController** must be defined in @Component.
13
14   ```ts
15   @CustomDialog
16   struct CustomDialogExample {
17     controller: CustomDialogController = new CustomDialogController({
18       builder: CustomDialogExample({}),
19     })
20
21     build() {
22       Column() {
23         Text('I am content')
24           .fontSize(20)
25       }.height(60).justifyContent(FlexAlign.Center)
26     }
27   }
28   ```
292. Create a builder that is bound to the decorator.
30
31   ```ts
32    @Entry
33    @Component
34    struct CustomDialogUser {
35      dialogController: CustomDialogController = new CustomDialogController({
36        builder: CustomDialogExample(),
37      })
38    }
39   ```
403. Click the component bound to the **onClick** event to display the dialog box.
41
42   ```ts
43   @Entry
44   @Component
45   struct CustomDialogUser {
46     dialogController: CustomDialogController = new CustomDialogController({
47       builder: CustomDialogExample(),
48     })
49
50     build() {
51       Column() {
52         Button('click me')
53           .onClick(() => {
54             this.dialogController.open()
55           })
56       }.width('100%').margin({ top: 5 })
57     }
58   }
59   ```
60
61   ![en-us_image_0000001562700493](figures/en-us_image_0000001562700493.png)
62
63## Implementing Interaction with the Custom Dialog Box
64
65Custom dialog boxes can be used for data interactions to complete a series of operations.
66
671. Add buttons in the \@CustomDialog decorator structure and add data functions.
68
69   ```ts
70   @CustomDialog
71   struct CustomDialogExample {
72     cancel?: () => void
73     confirm?: () => void
74     controller: CustomDialogController
75
76     build() {
77       Column() {
78         Text('I am content').fontSize(20).margin({ top: 10, bottom: 10 })
79         Flex({ justifyContent: FlexAlign.SpaceAround }) {
80           Button('Cancel')
81             .onClick(() => {
82               this.controller.close()
83               if (this.cancel) {
84                 this.cancel()
85               }
86             }).backgroundColor(0xffffff).fontColor(Color.Black)
87           Button('Obtain')
88             .onClick(() => {
89               this.controller.close()
90               if (this.confirm) {
91                 this.confirm()
92               }
93             }).backgroundColor(0xffffff).fontColor(Color.Red)
94         }.margin({ bottom: 10 })
95       }
96     }
97   }
98   ```
992. Receive the page in the builder and create corresponding function operations.
100
101   ```ts
102   @Entry
103   @Component
104   struct CustomDialogUser {
105     dialogController: CustomDialogController = new CustomDialogController({
106       builder: CustomDialogExample({
107         cancel: ()=> { this.onCancel() },
108         confirm: ()=> { this.onAccept() },
109       }),
110     })
111
112     onCancel() {
113       console.info('Callback when the first button is clicked')
114     }
115
116     onAccept() {
117       console.info('Callback when the second button is clicked')
118     }
119
120     build() {
121       Column() {
122         Button('click me')
123           .onClick(() => {
124             this.dialogController.open()
125           })
126       }.width('100%').margin({ top: 5 })
127     }
128   }
129   ```
130
131   ![en-us_image_0000001511421320](figures/en-us_image_0000001511421320.png)
132
133   3. Use the button in the dialog box to implement route redirection and obtain the parameters passed in from the redirection target page.
134
135   ```ts
136   // Index.ets
137   @CustomDialog
138   struct CustomDialogExample {
139     @Link textValue: string
140     controller?: CustomDialogController
141     cancel: () => void = () => {
142     }
143     confirm: () => void = () => {
144     }
145
146     build() {
147       Column({ space: 20 }) {
148         if (this.textValue != '') {
149           Text(`Content of the second page: ${this.textValue}`)
150             .fontSize(20)
151         } else {
152           Text('Obtain the content of the second page?')
153             .fontSize(20)
154         }
155         Flex({ justifyContent: FlexAlign.SpaceAround }) {
156           Button('Cancel')
157             .onClick(() => {
158               if (this.controller != undefined) {
159                 this.controller.close()
160                 this.cancel()
161               }
162             }).backgroundColor(0xffffff).fontColor(Color.Black)
163           Button('Obtain')
164             .onClick(() => {
165               if (this.controller != undefined && this.textValue != '') {
166                 this.controller.close()
167               } else if (this.controller != undefined) {
168                 this.getUIContext().getRouter().pushUrl({
169                   url: 'pages/Index2'
170                 })
171                 this.controller.close()
172               }
173             }).backgroundColor(0xffffff).fontColor(Color.Red)
174         }.margin({ bottom: 10 })
175       }.borderRadius(10).padding({ top: 20 })
176     }
177   }
178
179   @Entry
180   @Component
181   struct CustomDialogUser {
182     @State textValue: string = ''
183     dialogController: CustomDialogController | null = new CustomDialogController({
184       builder: CustomDialogExample({
185         cancel: () => {
186           this.onCancel()
187         },
188         confirm: () => {
189           this.onAccept()
190         },
191         textValue: $textValue
192       })
193     })
194
195     // Set dialogController to null when the custom component is about to be destroyed.
196     aboutToDisappear() {
197       this.dialogController = null // Set dialogController to null.
198     }
199
200     onPageShow() {
201       const params = this.getUIContext().getRouter().getParams() as Record<string, string>; // Obtain the passed parameter object.
202       if (params) {
203         this.dialogController?.open()
204         this.textValue = params.info as string; // Obtain the value of the id attribute.
205       }
206     }
207
208     onCancel() {
209       console.info('Callback when the first button is clicked')
210     }
211
212     onAccept() {
213       console.info('Callback when the second button is clicked')
214     }
215
216     exitApp() {
217       console.info('Click the callback in the blank area')
218     }
219
220     build() {
221       Column() {
222         Button('Click Me')
223           .onClick(() => {
224             if (this.dialogController != null) {
225               this.dialogController.open()
226             }
227           }).backgroundColor(0x317aff)
228       }.width('100%').margin({ top: 5 })
229     }
230   }
231   ```
232
233   ```ts
234   // Index2.ets
235   @Entry
236   @Component
237   struct Index2 {
238     @State message: string =' Back';
239
240     build() {
241       Column() {
242         Button(this.message)
243           .type(ButtonType.Capsule)
244           .onClick(() => {
245              this.getUIContext().getRouter().back({
246                url: 'pages/Index',
247                params: {
248                info: 'Hello World'
249              }
250           });
251         })
252       }.width('100%').height('100%').margin({ top: 20 })
253     }
254   }
255   ```
256
257   ![DialogRouter](figures/DialogRouter.gif)
258
259## Defining the Custom Dialog Box Animation
260
261You can define the custom dialog box animation, including its duration and speed, through **openAnimation**.
262
263```ts
264@CustomDialog
265struct CustomDialogExample {
266  controller?: CustomDialogController
267
268  build() {
269    Column() {
270      Text('Whether to change a text?').fontSize(16).margin({ bottom: 10 })
271    }
272  }
273}
274
275@Entry
276@Component
277struct CustomDialogUser {
278  @State textValue: string = ''
279  @State inputValue: string = 'click me'
280  dialogController: CustomDialogController | null = new CustomDialogController({
281    builder: CustomDialogExample(),
282    openAnimation: {
283      duration: 1200,
284      curve: Curve.Friction,
285      delay: 500,
286      playMode: PlayMode.Alternate,
287      onFinish: () => {
288        console.info('play end')
289      }
290    },
291    autoCancel: true,
292    alignment: DialogAlignment.Bottom,
293    offset: { dx: 0, dy: -20 },
294    gridCount: 4,
295    customStyle: false,
296    backgroundColor: 0xd9ffffff,
297    cornerRadius: 10,
298  })
299
300  // Set dialogController to null when the custom component is about to be destroyed.
301  aboutToDisappear() {
302    this.dialogController = null // Set dialogController to null.
303  }
304
305  build() {
306    Column() {
307      Button(this.inputValue)
308        .onClick(() => {
309          if (this.dialogController != null) {
310            this.dialogController.open()
311          }
312        }).backgroundColor(0x317aff)
313    }.width('100%').margin({ top: 5 })
314  }
315}
316```
317
318![openAnimator](figures/openAnimator.gif)
319
320## Defining the Custom Dialog Box Style
321
322You can set style parameters, such as the width, height, background color, and shadow, for a custom dialog box.
323
324```ts
325@CustomDialog
326struct CustomDialogExample {
327  controller?: CustomDialogController
328
329  build() {
330    Column() {
331      Text('I am content').fontSize(16).margin({ bottom: 10 })
332    }
333  }
334}
335
336@Entry
337@Component
338struct CustomDialogUser {
339  @State textValue: string = ''
340  @State inputValue: string = 'Click Me'
341  dialogController: CustomDialogController | null = new CustomDialogController({
342    builder: CustomDialogExample(),
343    autoCancel: true,
344    alignment: DialogAlignment.Center,
345    offset: { dx: 0, dy: -20 },
346    gridCount: 4,
347    customStyle: false,
348    backgroundColor: 0xd9ffffff,
349    cornerRadius: 20,
350    width: '80%',
351    height: '100px',
352    borderWidth: 1,
353    borderStyle: BorderStyle.Dashed,// borderStyle must be used with borderWidth in pairs.
354    borderColor: Color.Blue,// borderColor must be used with borderWidth in pairs.
355    shadow: ({ radius: 20, color: Color.Grey, offsetX: 50, offsetY: 0}),
356  })
357
358  // Set dialogController to null when the custom component is about to be destroyed.
359  aboutToDisappear() {
360    this.dialogController = null // Set dialogController to null.
361  }
362
363  build() {
364    Column() {
365      Button(this.inputValue)
366        .onClick(() => {
367          if (this.dialogController != null) {
368            this.dialogController.open()
369          }
370        }).backgroundColor(0x317aff)
371    }.width('100%').margin({ top: 5 })
372  }
373}
374```
375
376![custom_style](figures/custom_style.gif)
377
378## Nesting a Custom Dialog Box
379
380To nest a dialog box (dialog 2) inside another dialog box (dialog 1), it is recommended that you define dialog 2 within the parent component of dialog 1 so that you can then open dialog 2 through the callback sent from the parent component to dialog 1.
381
382```ts
383@CustomDialog
384struct CustomDialogExampleTwo {
385  controllerTwo?: CustomDialogController
386  @State message: string = "I'm the second dialog box."
387  @State showIf: boolean = false;
388  build() {
389    Column() {
390      if (this.showIf) {
391        Text("Text")
392          .fontSize(30)
393          .height(100)
394      }
395      Text(this.message)
396        .fontSize(30)
397        .height(100)
398      Button("Create Text")
399        .onClick(()=>{
400          this.showIf = true;
401        })
402      Button('Close Second Dialog Box')
403        .onClick(() => {
404          if (this.controllerTwo != undefined) {
405            this.controllerTwo.close()
406          }
407        })
408        .margin(20)
409    }
410  }
411}
412@CustomDialog
413struct CustomDialogExample {
414  openSecondBox?: ()=>void
415  controller?: CustomDialogController
416
417  build() {
418    Column() {
419      Button('Open Second Dialog Box and Close This Box')
420        .onClick(() => {
421          this.controller!.close();
422          this.openSecondBox!();
423        })
424        .margin(20)
425    }.borderRadius(10)
426  }
427}
428@Entry
429@Component
430struct CustomDialogUser {
431  @State inputValue: string = 'Click Me'
432  dialogController: CustomDialogController | null = new CustomDialogController({
433    builder: CustomDialogExample({
434      openSecondBox: ()=>{
435        if (this.dialogControllerTwo != null) {
436          this.dialogControllerTwo.open()
437        }
438      }
439    }),
440    cancel: this.exitApp,
441    autoCancel: true,
442    alignment: DialogAlignment.Bottom,
443    offset: { dx: 0, dy: -20 },
444    gridCount: 4,
445    customStyle: false
446  })
447  dialogControllerTwo: CustomDialogController | null = new CustomDialogController({
448    builder: CustomDialogExampleTwo(),
449    alignment: DialogAlignment.Bottom,
450    offset: { dx: 0, dy: -25 } })
451
452  aboutToDisappear() {
453    this.dialogController = null
454    this.dialogControllerTwo = null
455  }
456
457  onCancel() {
458    console.info('Callback when the first button is clicked')
459  }
460
461  onAccept() {
462    console.info('Callback when the second button is clicked')
463  }
464
465  exitApp() {
466    console.info('Click the callback in the blank area')
467  }
468  build() {
469    Column() {
470      Button(this.inputValue)
471        .onClick(() => {
472          if (this.dialogController != null) {
473            this.dialogController.open()
474          }
475        }).backgroundColor(0x317aff)
476    }.width('100%').margin({ top: 5 })
477  }
478}
479```
480
481![nested_dialog](figures/nested_dialog.gif)
482
483If you define dialog 2 within dialog 1 instead, because of the parent-child relationship that exists between custom dialog boxes in terms of state management, you will not be able to create any component in dialog 2 once dialog 1 is destroyed (closed).
484
485