We use essential cookies for the website to function, as well as analytics cookies for analyzing and creating statistics of the website performance. To agree to the use of analytics cookies, click "Accept All". You can manage your preferences at any time by clicking "Cookie Settings" on the footer. More Information.

Only Essential Cookies
Accept All
GuidesApplication FrameworkArkUIUI Development (ArkTS-based Declarative Development Paradigm)Using Popup WindowsCustom Dialog Selection and Development

Custom Dialog Selection and Development

Overview

When developing dialogs, you need to select the appropriate implementation scheme based on the dialog type. Common dialog types include text prompt dialogs, confirmation dialogs, menus, and action sheets. This section delves into the fundamental types of dialogs and their features, incorporating currently recommended dialog types, supported capabilities, and practical usage suggestions to introduce the selection and development process for dialogs, to help you address common issues encountered when using dialogs (for example, implementing swipe interception and ensuring dialog persist after returning from page navigation).

Dialog Capabilities

This section introduces dialog capabilities from three aspects:

  • Key characteristics: introduces common requirements that you may have for dialogs from the perspective of interaction.
  • Capability support: describes the specific capabilities and functions supported by the recommended dialog solutions.
  • Usage suggestions: compares the differences among the recommended dialog solutions and provides suggestions for dialog selection.

Key Characteristics of Dialogs

In addition to the content and style of dialogs, there are several common interaction demands from the perspective of user interaction.

Expand
Interaction Demand Display Effect Interaction Demand Display Effect Interaction Demand Display Effect
Swipe-to-close: Decide whether the dialog should close on swipe gestures. This is often interaction-driven to prevent users from exiting too easily. Tap-outside-to-close: When the dialog content is critical, disallow closing the dialog by tapping outside to ensure user engagement and processing. Custom animations: Determine whether you need to configure custom entry and exit animations and their types.
Content retention upon navigation: Decide whether the dialog content should remain on the previous page after navigation, such as with privacy dialogs. Focus capture: Some custom dialogs implemented with dialog components grab focus on display, which can cause the keyboard to retract and then reappear. ) Keyboard avoidance: Ensure that the dialog and its content are not obscured when the keyboard is up, though there are scenarios where this is not necessary, like with comment reply dialogs.

Capability Support

Currently, the system provides a variety of custom dialog capabilities, detailed as follows:

  • Recommended dialogs

    1. UIContext based custom dialogs: UIContext dialogs are a context-based dialog management mechanism. By encapsulating content with ComponentContent, they decouple from the UI, offering flexible invocation that meets your encapsulation needs. These dialogs provide high flexibility with fully customizable styles. When the associated UIContext is destroyed (for example, when a page is closed), the dialog automatically closes without manual management. Additionally, dialog hierarchy is managed by the UIContext, decoupled from page routing, making it suitable for complex scenarios. Currently, the main APIs for implementing dialogs include UIContext.openBindSheet(), UIContext.getPromptAction().openCustomDialog(), and UIContext.getOverlayManager().

    2. Custom dialog box implemented based on Navigation.Dialog: NavDestination.Dialog is a dialog box effect implemented based on the Navigation component. It is essentially a route page and exists in the route stack. It can be used to implement modal and semi-modal forms and is applicable to scenarios such as transparent pages and pages where the dialog box does not disappear during page switching.

      These dialogs offer good flexibility and extensibility in their technical implementation, with strong support for page decoupling and custom dialog styling. For details about their capabilities, see Capability support.

  • Not recommended dialogs

    1. Basic Custom Dialog (\CustomDialog): CustomDialogController has many restrictions on usage. It does not support dynamic creation or refresh and can only be used within custom components decorated with @Component. This means that dialog creation and management are tightly coupled with specific components, increasing code complexity and maintenance costs. Moreover, when a single page needs to display multiple custom dialogs, each dialog must have its own CustomDialogController declared, leading to redundant UI layer code and making it difficult to decouple dialog logic from page logic.
    2. @ohos.promptAction (prompt): @ohos.promptAction is a global method that can cause issues when executed without a UIContext. You may also face problems if you cannot specify a UIContext, potentially causing the prompt to appear in an unintended window. For these reasons, it is not recommended. Additionally, it uses the system's default dialog style, which does not allow for extensive custom styling. It is suitable for simple alert-type dialogs that need to maintain a consistent system look and feel but has a limited scope of application.

Due to the differences in dialog types, there are certain limitations in terms of functionality, interaction experience, and applicable scenarios. The recommended dialog capabilities are summarized in the following table for reference.

Expand
Description UIContext.openBindSheet() UIContext.getPromptAction().openCustomDialog() UIContext.getOverlayManager() NavDestination.Dialog
Swipe-to-close response √ √ √ √
Tap-outside-to-close √ √ × ×
Custom entry and exit animations × √ Partially supported (Animations are not supported by default. You can customize an animation.) Partially supported (System transition animations are supported since API version 13.)
Dialog persistence across page switches √ √ √ √
Focus handling √ √ √ √
Keyboard avoidance mode × √ ⍻ (Set it based on the window.) ⍻ (Set it based on the window.)

In addition to the six scenarios mentioned above, which correspond to common interaction demands, there are other capability support situations, such as whether the dialog supports decoupling from the page and custom dialog styling, as detailed below.

Expand
Description UIContext.openBindSheet() UIContext.getPromptAction().openCustomDialog() UIContext.getOverlayManager() NavDestination.Dialog
Page decoupling √ √ √ √
Custom dialog styling (background, rounded corners, and more) √ √ √ √
Dialog overlay √ √ √ √
Layer management √ √ √ √
Route decoupling √ √ √ ×
Event dispatch to page × × √ √

Usage Suggestions of Dialogs

Currently, UIContext dialogs and Navigation dialogs are the main recommended dialog types. They differ in terms of position and presentation, as well as applicable scenarios. You are advised to choose based on development needs and specific scenarios.

Expand
Dialog Type Position and Presentation Scenario
UIContext.openBindSheet() Such a dialog typically slides up from the bottom. It is semi-modal and occupies part of the screen height. Suitable for displaying a list of bottom operation options, such as bottom operations and list options.
UIContext.getPromptAction().openCustomDialog() Such a dialog is centrally displayed by default. It can be set to modal or non-modal through the isModal parameter. Suitable for various scenarios requiring highly customizable dialog content and styles, such as operation confirmation prompts and form input dialogs.
UIContext.getOverlayManager() Such a dialog can be displayed at any position on the screen. It is independent of page layout and overlays all components beneath the dialog. Used for implementing global floating tips or operation buttons, such as customer service entry balls, event icon entries, and guide prompts.
NavDestination.Dialog Such a dialog is based on Navigation. It exists in the route stack as a Component page and is transparent by default. Suitable for all forms of dialogs. Note that this dialog is actually implemented as a page and occupies the page stack.

Implementation of Common Dialog Scenarios

Based on different service requirements, there are various types of dialogs to choose from. This section selects several common dialog implementation cases and introduces them in combination with their corresponding capability features.

Implementing an Image-Text Prompt Dialog (Similar to Toast)

Image-text prompt dialogs are commonly used to display the results of user operations, such as success or failure messages, and can also show loading animations while waiting for system responses.

Implementation

showToast supports only text s and cannot implement dialogs that contain both images and text. In such scenarios, you can use UIContext.getPromptAction().openCustomDialog().

Sample Code

Use @Builder to customize the buildText() function to encapsulate the content and style of the image-text prompt dialog and add an image and text to the dialog.

Collapse
Word wrap
Dark theme
Copy code
  1. @Builder
  2. function buildText(params: Params) {
  3. Row() {
  4. Image($r('app.media.checkmark_circle'))
  5. .width(24)
  6. .height(24)
  7. .margin({ right: 16 })
  8. Text(params.text)
  9. .fontSize(16)
  10. }
  11. .justifyContent(FlexAlign.Center)
  12. .backgroundColor(Color.White)
  13. .padding({ left: 24, right: 24 })
  14. .height(50)
  15. .borderRadius(24)
  16. }

Use UIContext.getPromptAction().openCustomDialog() to open a dialog and use BaseDialogOptions to configure the dialog style.

Collapse
Word wrap
Dark theme
Copy code
  1. let uiContext = this.getUIContext();
  2. PromptActionClass.setContext(uiContext);
  3. imageTipsContentNode = new ComponentContent(getUIContext, wrapBuilder(buildText), new Params(this.message));
  4. PromptActionClass.setContentNode(imageTipsContentNode);
  5. PromptActionClass.setOptions({
  6. isModal: false,
  7. alignment: DialogAlignment.Bottom,
  8. offset: { dx: 0, dy: -80 },
  9. focusable: false
  10. });
  11. PromptActionClass.openDialog();
  12. setTimeout(() => {
  13. PromptActionClass.closeDialog(imageTipsContentNode);
  14. }, 3000)

Note that dialogs will preempt focus when they display. If there is a text input box currently in use, this will cause the keyboard to retract. In scenarios where the original UI usability needs to be maintained, users may want the dialog to not proactively obtain focus to avoid interrupting their current operations. In this case, you can set the focusable attribute of the promptAction.BaseDialogOptions to false, which means that the dialog is not allowed to obtain focus.

Collapse
Word wrap
Dark theme
Copy code
  1. PromptActionClass.setOptions({
  2. isModal: false,
  3. alignment: DialogAlignment.Bottom,
  4. offset: { dx: 0, dy: -80 },
  5. focusable: false
  6. });

Implementing a Privacy Dialog

Privacy dialogs are primarily used to ensure legal compliance, requiring applications to obtain user consent before collecting user data. When users open a privacy dialog, they can tap hyperlinks within the dialog to navigate to detailed privacy policy pages. Upon returning, the privacy dialog remains visible, ensuring that users can make informed decisions based on the information provided.

In the privacy page, there are two main points to consider:

  1. When users tap the privacy policy link within the privacy dialog and navigate to a new page, the dialog should remain beneath the new page, and its state should be preserved when returning to the original page.

  2. When users perform a swipe gesture, you can set up an interception to prevent the swipe operation, requiring users to exit the dialog by clicking Accept or Decline.

Implementation

Since API version 16, you can use UIContext.getPromptAction().openCustomDialog() to implement this feature. It allows you to configure page-level dialogs using levelMode and levelUniqueId.

  • Dialog persistence across page switches

    Import the custom dialog wrapper class PromptActionClass, which defines the methods for opening and closing the dialog and setting options.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. import { PromptActionClass } from '../utils/PromptActionClass';

    Use levelMode and levelUniqueId in BaseDialogOptions to set up the dialog to appear within a specific page. The two parameters task a node ID within the page. After the parameters are set, the dialog will automatically query the Navigation page corresponding to this ID and mount itself under that page. As shown in the following code example, the Button node is the node of the specified page. After the custom ID is set, the getFrameNodeById() method is used to obtain the node, and then the getUniqueId method is used to obtain the internal ID of the node and pass it as the value of levelUniqueId.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. Column() {
    2. Row() {
    3. Image($r('app.media.chevron_left'))
    4. .width(16)
    5. .height(16)
    6. .margin({ left: 12 })
    7. }
    8. .width(40)
    9. .height(40)
    10. .borderRadius(48)
    11. .margin({ top: 42 })
    12. .backgroundColor('#e6eaeb')
    13. .onClick(() => {
    14. this.pageStack.pop();
    15. })
    16. Row() {
    17. Button('OPEN')
    18. .id('privacyDialog')
    19. .fontSize(16)
    20. .width('100%')
    21. .borderRadius(20)
    22. .margin({ bottom: 16 })
    23. .backgroundColor('#0A59F7')
    24. .onClick(() => {
    25. const node: FrameNode | null = this.getUIContext().getFrameNodeById('privacyDialog');
    26. let uiContext = this.getUIContext();
    27. PromptActionClass.setContext(uiContext);
    28. PromptActionClass.setContentNode(privacyContentNode);
    29. PromptActionClass.setOptions({
    30. levelMode: LevelMode.EMBEDDED,
    31. levelUniqueId: node?.getUniqueId(),
    32. onWillDismiss: (dismissDialogAction: DismissDialogAction) => {
    33. hilog.info(0xFF00, 'TAG', JSON.stringify(dismissDialogAction.reason));
    34. }
    35. })
    36. PromptActionClass.openDialog();
    37. })
    38. }
    39. .width('100%')
    40. .alignItems(VerticalAlign.Center)
    41. }
    42. .width('100%')
    43. .height('100%')
    44. .padding({
    45. left: 16,
    46. right: 16,
    47. bottom: 32
    48. })
    49. .justifyContent(FlexAlign.SpaceBetween)
    50. .alignItems(HorizontalAlign.Start)
  • Swipe interception

    Swipe interception is implemented through the onWillDismiss callback function of UIContext.getPromptAction(). When users perform operations such as tapping outside the dialog, swiping from the edge, pressing the Back button, or pressing the ESC key on the keyboard, registering this callback prevents the dialog from closing immediately. Within the callback, you can use the enum DismissReason to determine the reason for the closure and decide whether to close the dialog.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. PromptActionClass.setOptions({
    2. levelMode: LevelMode.EMBEDDED,
    3. levelUniqueId: node?.getUniqueId(),
    4. onWillDismiss: (dismissDialogAction: DismissDialogAction) => {
    5. hilog.info(0xFF00, 'TAG', JSON.stringify(dismissDialogAction.reason));
    6. }
    7. })

For API versions prior to 16, you can implement the dialog using NavDestinationMode.DIALOG. Essentially, this approach retains the dialog by managing it as a route page within the navigation stack.

Implementation using NavDestinationMode.DIALOG

  • Dialog persistence across page switches

    If you implement the dialog using NavDestinationMode.DIALOG, you need to set the display mode (specified by mode) of NavDestination to NavDestinationMode.DIALOG.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. NavDestination() {
    2. // ... Dialog content.
    3. }
    4. .mode(NavDestinationMode.DIALOG)
  • Swipe interception

    Implement swipe interception using the onBackPressed() callback of NavDestination. When the physical back button is tapped or a swipe gesture is used, this callback is triggered. If the return value is true, the back button logic is overridden, thereby implementing swipe interception.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. NavDestination() {
    2. // ...
    3. }
    4. .hideTitleBar(true)
    5. .mode(NavDestinationMode.DIALOG)
    6. .onBackPressed((): boolean => {
    7. return true;
    8. })

Implementing a Progress Bar Dialog

Progress bar dialogs are a common type of dialog used to provide user feedback on task progress during time-consuming operations. The key feature of these dialogs is the data interaction between the dialog and the page, which involves refreshing the dialog content.

Implementation

  • Updating dialog content in the page

    The content of the custom component in the dialog can be updated using the update() method provided by ComponentContent. That is, the contentNode.update() updates the data in the dialog and synchronizes the data to the UI for display.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. Text(isProgressRunning ? $r('app.string.pause') : $r('app.string.start'))
    2. .fontSize(16)
    3. .fontColor('#0A59F7')
    4. .margin({ top: 8 })
    5. .onClick(() => {
    6. isProgressRunning = !isProgressRunning;
    7. if (isProgressRunning) {
    8. timer = setInterval(() => {
    9. if (value === 100) {
    10. value = 0;
    11. }
    12. value += 10;
    13. progressContentNode.update(new ProgressParams($r('app.string.progress'), value, isProgressRunning));
    14. }, 1000)
    15. } else {
    16. clearInterval(timer);
    17. }
    18. progressContentNode.update(new ProgressParams($r('app.string.progress'), value, isProgressRunning));
    19. })
  • Preventing dialog closure on outside tapping

    To ensure that the task continues running even after the progress bar dialog is closed, configure the dialog to not auto-cancel by setting autoCancel to true. This way, tapping outside the dialog does not interrupt the task flow. When the dialog is reopened, the progress bar continues updating based on the current task status.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. let uiContext = this.getUIContext();
    2. PromptActionClass.setContext(uiContext);
    3. progressContentNode = new ComponentContent(getUIContext, wrapBuilder(buildProgress),
    4. new ProgressParams($r('app.string.progress'), value, false));
    5. PromptActionClass.setContentNode(progressContentNode);
    6. PromptActionClass.setOptions({
    7. autoCancel: true,
    8. transition: TransitionEffect.asymmetric(
    9. TransitionEffect.OPACITY.animation({ duration: 1000 }),
    10. TransitionEffect.OPACITY.animation({ delay: 500, duration: 1000 })
    11. )
    12. })
    13. PromptActionClass.openDialog();
  • Customizing entry and exit animations

    In application development, the default system dialog animations often do not meet specific needs. To implement custom dialog entry and exit animations, you can use the following methods: fade in and fade out; slide in from the left and slide out to the right; slide up from the bottom and slide down to close. The following uses the fade-in/fade-out effect as an example to introduce custom dialog entry and exit animations.

    You can use the transition parameter of BaseDialogOptions to set the transition effect for displaying and exiting a dialog, thereby implementing the fade-in and fade-out effect for the display and exit animations of a custom dialog.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. transition: TransitionEffect.asymmetric(
    2. TransitionEffect.OPACITY.animation({ duration: 1000 }),
    3. TransitionEffect.OPACITY.animation({ delay: 500, duration: 1000 })
    4. )

Implementing a Bottom Operation Dialog

Bottom operation dialogs typically refer to the semi-modal menus triggered by tapping on the operation bar (such as the More button in the top-right corner) in an application screen. These dialogs usually feature functions like sharing, adding, deleting, modifying, and querying. The main content of the operation dialog is a list, which can be of fixed or variable height.

Implementation

Use openBindsheet to encapsulate the component content displayed on the semi-modal page through ComponentContent, and use SheetOptions to set the style of the semi-modal page.

  • Fixed-height operation dialog

    Set the height to SheetSize.MEDIUM for a fixed-height dialog that cannot be dragged by the user.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. Text($r('app.string.operation_list'))
    2. .onClick(() => {
    3. let contentNode =
    4. new ComponentContent(this.getUIContext(), wrapBuilder(buildActionList));
    5. let uiContext = this.getUIContext();
    6. let uniqueId = this.getUniqueId();
    7. let frameNode: FrameNode | null = uiContext.getFrameNodeByUniqueId(uniqueId);
    8. let targetId = frameNode?.getFirstChild()?.getUniqueId();
    9. uiContext.openBindSheet(contentNode, {
    10. title: { title: $r('app.string.more') },
    11. height: SheetSize.MEDIUM,
    12. backgroundColor: '#F1F3F5',
    13. preferType: SheetType.BOTTOM
    14. }, targetId)
    15. .then(() => {
    16. hilog.info(0xFF00, 'TAG', 'openBindSheet success');
    17. })
    18. .catch((err: BusinessError) => {
    19. hilog.info(0xFF00, 'TAG', 'openBindSheet error: ' + err.code + ' ' + err.message);
    20. })
    21. })
    22. .width('100%')
  • Variable-height operation dialog

    You can set the height to be variable by using the detents parameter of SheetOptions.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. uiContext.openBindSheet(contentNode, {
    2. title: { title: $r('app.string.more') },
    3. height: SheetSize.MEDIUM,
    4. backgroundColor: '#F1F3F5',
    5. preferType: SheetType.BOTTOM,
    6. detents: [SheetSize.MEDIUM, SheetSize.LARGE, 200]
    7. }, targetId)
    8. .then(() => {
    9. hilog.info(0xFF00, 'TAG', 'openBindSheet success');
    10. })
    11. .catch((err: BusinessError) => {
    12. hilog.info(0xFF00, 'TAG', 'openBindSheet error: ' + err.code + ' ' + err.message);
    13. })

Implementing a Comment Reply Dialog

The comment reply module is widely used in text and video applications. It includes an editing area, a friends list, a list of frequently used emojis, and an emoji panel (as shown in the figure below). It allows users to input text, emojis, tag friends, and select images. For details about the implementation solution, see Comment Dialog Box.

Search in Guides
Enter a keyword.