• 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** component. For details, see the [page display mode: dialog mode](arkts-navigation-navigation.md#page-display-mode).
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     build() {
240       Column() {
241         Button(this.message)
242           .fontWeight(FontWeight.Bold).onClick(() => {
243           this.getUIContext().getRouter().back({
244             url: 'pages/Index',
245             params: {
246               info: 'Hello World'
247             }
248           });
249         })
250       }.width('100%').height('100%').margin({ top: 20 })
251     }
252   }
253   ```
254
255   ![DialogRouter](figures/DialogRouter.gif)
256
257## Defining the Custom Dialog Box Animation
258
259You can define the custom dialog box animation, including its duration and speed, through **openAnimation**.
260
261```ts
262@CustomDialog
263struct CustomDialogExample {
264  controller?: CustomDialogController
265
266  build() {
267    Column() {
268      Text('Whether to change a text?').fontSize(16).margin({ bottom: 10 })
269    }
270  }
271}
272
273@Entry
274@Component
275struct CustomDialogUser {
276  @State textValue: string = ''
277  @State inputValue: string = 'click me'
278  dialogController: CustomDialogController | null = new CustomDialogController({
279    builder: CustomDialogExample(),
280    openAnimation: {
281      duration: 1200,
282      curve: Curve.Friction,
283      delay: 500,
284      playMode: PlayMode.Alternate,
285      onFinish: () => {
286        console.info('play end')
287      }
288    },
289    autoCancel: true,
290    alignment: DialogAlignment.Bottom,
291    offset: { dx: 0, dy: -20 },
292    gridCount: 4,
293    customStyle: false,
294    backgroundColor: 0xd9ffffff,
295    cornerRadius: 10,
296  })
297
298  // Set dialogController to null when the custom component is about to be destroyed.
299  aboutToDisappear() {
300    this.dialogController = null // Set dialogController to null.
301  }
302
303  build() {
304    Column() {
305      Button(this.inputValue)
306        .onClick(() => {
307          if (this.dialogController != null) {
308            this.dialogController.open()
309          }
310        }).backgroundColor(0x317aff)
311    }.width('100%').margin({ top: 5 })
312  }
313}
314```
315
316![openAnimator](figures/openAnimator.gif)
317
318## Defining the Custom Dialog Box Style
319
320You can set style parameters, such as the width, height, background color, and shadow, for a custom dialog box.
321
322```ts
323@CustomDialog
324struct CustomDialogExample {
325  controller?: CustomDialogController
326
327  build() {
328    Column() {
329      Text('I am content').fontSize(16).margin({ bottom: 10 })
330    }
331  }
332}
333
334@Entry
335@Component
336struct CustomDialogUser {
337  @State textValue: string = ''
338  @State inputValue: string = 'Click Me'
339  dialogController: CustomDialogController | null = new CustomDialogController({
340    builder: CustomDialogExample(),
341    autoCancel: true,
342    alignment: DialogAlignment.Center,
343    offset: { dx: 0, dy: -20 },
344    gridCount: 4,
345    customStyle: false,
346    backgroundColor: 0xd9ffffff,
347    cornerRadius: 20,
348    width: '80%',
349    height: '100px',
350    borderWidth: 1,
351    borderStyle: BorderStyle.Dashed,// borderStyle must be used with borderWidth in pairs.
352    borderColor: Color.Blue,// borderColor must be used with borderWidth in pairs.
353    shadow: ({ radius: 20, color: Color.Grey, offsetX: 50, offsetY: 0}),
354  })
355
356  // Set dialogController to null when the custom component is about to be destroyed.
357  aboutToDisappear() {
358    this.dialogController = null // Set dialogController to null.
359  }
360
361  build() {
362    Column() {
363      Button(this.inputValue)
364        .onClick(() => {
365          if (this.dialogController != null) {
366            this.dialogController.open()
367          }
368        }).backgroundColor(0x317aff)
369    }.width('100%').margin({ top: 5 })
370  }
371}
372```
373
374![custom_style](figures/custom_style.gif)
375
376## Nesting a Custom Dialog Box
377
378To 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.
379
380```ts
381@CustomDialog
382struct CustomDialogExampleTwo {
383  controllerTwo?: CustomDialogController
384  @State message: string = "I'm the second dialog box."
385  @State showIf: boolean = false;
386  build() {
387    Column() {
388      if (this.showIf) {
389        Text("Text")
390          .fontSize(30)
391          .height(100)
392      }
393      Text(this.message)
394        .fontSize(30)
395        .height(100)
396      Button("Create Text")
397        .onClick(()=>{
398          this.showIf = true;
399        })
400      Button('Close Second Dialog Box')
401        .onClick(() => {
402          if (this.controllerTwo != undefined) {
403            this.controllerTwo.close()
404          }
405        })
406        .margin(20)
407    }
408  }
409}
410@CustomDialog
411struct CustomDialogExample {
412  openSecondBox?: ()=>void
413  controller?: CustomDialogController
414
415  build() {
416    Column() {
417      Button('Open Second Dialog Box and Close This Box')
418        .onClick(() => {
419          this.controller!.close();
420          this.openSecondBox!();
421        })
422        .margin(20)
423    }.borderRadius(10)
424  }
425}
426@Entry
427@Component
428struct CustomDialogUser {
429  @State inputValue: string = 'Click Me'
430  dialogController: CustomDialogController | null = new CustomDialogController({
431    builder: CustomDialogExample({
432      openSecondBox: ()=>{
433        if (this.dialogControllerTwo != null) {
434          this.dialogControllerTwo.open()
435        }
436      }
437    }),
438    cancel: this.exitApp,
439    autoCancel: true,
440    alignment: DialogAlignment.Bottom,
441    offset: { dx: 0, dy: -20 },
442    gridCount: 4,
443    customStyle: false
444  })
445  dialogControllerTwo: CustomDialogController | null = new CustomDialogController({
446    builder: CustomDialogExampleTwo(),
447    alignment: DialogAlignment.Bottom,
448    offset: { dx: 0, dy: -25 } })
449
450  aboutToDisappear() {
451    this.dialogController = null
452    this.dialogControllerTwo = null
453  }
454
455  onCancel() {
456    console.info('Callback when the first button is clicked')
457  }
458
459  onAccept() {
460    console.info('Callback when the second button is clicked')
461  }
462
463  exitApp() {
464    console.info('Click the callback in the blank area')
465  }
466  build() {
467    Column() {
468      Button(this.inputValue)
469        .onClick(() => {
470          if (this.dialogController != null) {
471            this.dialogController.open()
472          }
473        }).backgroundColor(0x317aff)
474    }.width('100%').margin({ top: 5 })
475  }
476}
477```
478
479![nested_dialog](figures/nested_dialog.gif)
480
481If 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).
482
483