弹窗概述

弹窗一般指打开应用时自动弹出或者用户行为操作时弹出的UI界面,用于短时间内展示用户需关注的信息或待处理的操作。

从ArkUI组件树层级上来看,Overlay浮层、弹窗、模态、带Order的Overlay浮层都挂载在Root节点下。弹窗、模态、带Order的Overlay浮层根据设置的层级(数字大小)进行逐层显示,并且全部显示在Overlay浮层上面。如图所示:

对于一个多页面应用,基本树结构如下所示。多个Page页面之间使用Router的接口进行跳转。NavBarNavdestination组成的页面可以通过Navigation接口进行跳转。

DialogPopupMenuOverlayManagerToastbindSheet以及bindContentCover的组件在结合路由、导航使用时存在如下几种显示模式。

  • 弹窗显示在当前应用窗口最上层,层级高于应用主窗内所有页面(默认行为)。

    如下图所示,触发弹窗显示时,弹窗层级要高于Page页面和Navigation页面,即如果弹窗组件没有被关闭的话,页面切换前后,弹窗组件都会显示在页面上方,而不会出现新的路由/导航页面覆盖在弹窗之上的情况。

    说明

    如果Popup或Menu等存在绑定组件的弹窗组件,在页面跳转后因为所绑定的组件不在新页面显示,系统内部会自动关闭对应弹窗组件。但因为弹窗组件显示同时受开发者配置的参数控制,例如当Popup的show参数设置为显示时,弹窗组件会覆盖在下一个页面上显示。

  • 弹窗显示在当前页面内,层级低于下一跳页面。

    当开发者期望弹窗是一个页面内的弹窗,即当路由/导航切换页面时,弹窗会被跳转的页面覆盖,随着页面切回原页面,弹窗仍然正常显示。此时弹窗层级如下图所示:

    页面级弹窗功能需要结合弹窗组件的页面级能力使用,当前支持页面级能力的有DialogbindSheet

  • 弹窗显示在独立窗口内,窗口层级高于应用所在窗口。

    在PC/2in1等设备上,开发者常期望弹窗的显示在应用窗口之外,此时需要借助子窗的能力。例如自定义弹窗可以通过CustomDialogControllerOptions中的showInSubwindow属性控制是否使用子窗功能。基于子窗显示的弹窗效果如下图所示。

    此时弹窗组件的显示层级受窗口的层级管理控制,会高于当前应用所在的窗口,低于系统窗口(如系统输入法、系统弹窗等)。

弹窗的种类

根据用户交互操作场景,弹窗可分为模态弹窗非模态弹窗两种类型,其区别在于用户是否必须对其做出响应。

  • 模态弹窗: 为强交互形式,会中断用户当前的操作流程,要求用户必须做出响应才能继续其他操作,通常用于需要向用户传达重要信息的场景。
  • 非模态弹窗: 为弱交互形式,不会影响用户当前操作行为,用户可以不对其进行回应,通常都有时间限制,出现一段时间后会自动消失。一般用于告诉用户信息内容外还需要用户进行功能操作的场景。

说明

当前模态弹窗通过设置指定属性变成非模态,例如AlertDialog,可以设置AlertDialogParam中的isModal属性值为false变成非模态,其他弹窗详见API说明。

不建议在非前台状态下,调用弹窗显示接口

系统弹窗由系统弹出,出于安全考虑,不支持自定义样式

系统弹窗出现时,调用非系统弹窗的显示接口(例如:promptActionopenCustomDialogCustomDialogControlleropen等),禁止该类弹窗显示。

使用场景

开发者可根据实际应用场景选择合适的弹窗进行页面开发

弹窗名称 应用场景
弹出框(Dialog) 当需要展示用户当前需要或必须关注的信息内容或操作时,例如二次退出应用等,应优先考虑使用此弹出框。
菜单(Menu/openMenu) 当需要给用户提供可执行的操作时,例如长按图标展示操作选项等,应优先考虑使用此弹窗。
气泡提示(Popup/openPopup) 当需要给用户提供提示时,例如点击一个问号图标弹出一段帮助提示等,应优先考虑使用此弹窗。
绑定模态页面(bindContentCover/bindSheet) 当需要新的界面覆盖在旧的界面上,且旧的界面不消失的一种转场方式时,例如缩略图片点击后查看大图等,应优先考虑使用此弹窗。
即时反馈(Toast) 当需要在一个小的窗口中提供用户当前操作的简单反馈时,例如提示文件保存成功等,应优先考虑使用此弹窗。
设置浮层(OverlayManager) 当需要完全自定义内容、行为、样式时,可以使用浮层将UI展示在页面之上,例如音乐/语音播放悬浮球/胶囊等,应优先考虑使用此弹窗。

规格约束

  • 多个弹窗组件先后弹出时,后弹出的组件的层级高于先弹出的层级,退出时按照层级从高到低的顺序逐次退出。

  • 在移动设备中,子窗模式的弹窗当前无法超出主窗口。而在2in1设备上,使用模态类弹窗时,会出现需要超出主窗口显示的场景,开发者可以通过设置showInSubWindow为true实现超出主窗口的显示效果。如下图所示:

固定样式弹框

固定样式弹出框采用固定的布局格式,这使得开发者无需关心具体的显示布局细节,只需输入所需显示的文本内容,从而简化了使用流程,提升了便捷性。

接口概览

使用约束

  • 可以通过调用UIContext或getUIContext,在非UI页面或某些异步回调中使用本文中的接口。CalendarPickerDialog当前不支持此操作。

  • 操作菜单 (showActionMenu)、对话框 (showDialog)需先使用UIContext中的getPromptAction()方法获取到PromptAction对象,再通过该对象调用对应方法。

  • 列表选择弹出框 (ActionSheet)、警告弹出框 (AlertDialog)、选择器弹出框 (PickerDialog)中除CalendarPickerDialog都需先使用ohos.window中的getUIContext()方法获取UIContext实例,再通过此实例调用对应方法。或者可以通过自定义组件内置方法getUIContext()获取。

操作菜单 (showActionMenu)、对话框 (showDialog)、列表选择弹出框 (ActionSheet)、警告弹出框 (AlertDialog)可以设置isModal为false变成非模态弹窗。

操作菜单 (showActionMenu)、对话框 (showDialog)、列表选择弹出框 (ActionSheet)和警告弹出框 (AlertDialog)不支持设置内容区的字体样式,如字体颜色、大小换行等操作,如需自定义样式,建议使用不依赖UI组件的全局自定义弹出框或者基础自定义弹出框

注意:不是所有固定弹框都不能设置样式,只能设置部分内容样式,每个固定弹框允许设置的内容样式内容不一样,需要具体参考各固定弹窗的指南。

生命周期

弹出框提供了生命周期函数,用于通知用户该弹出框的生命周期。生命周期的触发时序依次为:onWillAppear -> onDidAppear -> onWillDisappear -> onDidDisappear,也可参照各组件API。

从API version 19开始,对话框(showDialog)、列表选择弹出框(ActionSheet)、警告弹出框(AlertDialog)支持以下生命周期。

名称 类型 说明
onWillAppear Callback<void> 弹出框显示动效前的事件回调。
onDidAppear Callback<void> 弹出框弹出后的事件回调。
onWillDisappear Callback<void> 弹出框退出动效前的事件回调。
onDidDisappear Callback<void> 弹出框消失后的事件回调。

即时反馈(Toast)

使用步骤

  1. 页面中通过import导入PromptAction:import { PromptAction } from '@kit.ArkUI';
  2. 通过使用UIContext中的getPromptAction获取当前UI上下文关联的PromptAction对象:private promptAction: PromptAction = this.uicontext.getPromptAction();

  3. 再通过该对象调用showToast创建并显示文本提示框

    this.promptAction.showToast({

    message:‘保存成功',//弹窗显示内容

    duration: 2000//弹窗显示时间

    })

显示模式

操作菜单 (showActionMenu)

操作菜单通过UIContext中的getPromptAction方法获取到PromptAction对象,再通过该对象调用showActionMenu接口实现,支持在回调或开发者自定义类中使用。

操作菜单中,title字段的字体最大放大倍数为2。

创建并显示操作菜单后,菜单的响应结果会异步返回选中按钮在buttons数组中的索引。

例子参考固定样式弹框

对话框 (showDialog)

对话框通过UIContext中的getPromptAction方法获取到PromptAction对象,再通过该对象调用showDialog接口实现,支持在回调或开发者自定义类中使用。

对话框中,title字段的字体最大放大倍数为2。

创建并显示对话框,对话框响应后异步返回选中按钮在buttons数组中的索引。

 例子参考固定样式弹框

选择器弹窗 (PickerDialog)

选择器弹窗通常用于在用户进行某些操作(如点击按钮)时显示特定的信息或选项。

日历选择器弹窗 (CalendarPickerDialog)

日历选择器弹窗提供日历视图,包含年、月和星期信息,通过CalendarPickerDialog接口实现。开发者可调用show函数,定义并弹出日历选择器弹窗。

日历选择器弹窗的弹出依赖UI的执行上下文,不可在UI上下文不明确的地方使用,具体约束参见UIContext说明。

通过配置CalendarDialogOptions中的acceptButtonStyle、cancelButtonStyle属性可以实现自定义按钮样式。

 例子参考固定样式弹框

日期滑动选择器弹窗 (DatePickerDialog)

开发者可以利用指定的日期范围,创建日期滑动选择器弹窗,将日期信息清晰地展示在弹出的窗口上。

日期滑动选择器弹窗通过UIContext中的showDatePickerDialog接口实现。

弹窗中配置DatePickerDialogOptions的lunarSwitch、showTime属性为true时,会展示切换农历的开关和时间,当checkbox被选中时,会显示农历。当按下确定按钮时,弹窗会通过onDateAccept返回目前所选中的日期。如需弹窗再次弹出时显示选中的是上一次确定的日期,就要在回调中重新给selectTime进行赋值。

 例子参考固定样式弹框

通过配置disappearTextStyle、textStyle、selectedTextStyle、acceptButtonStyle、cancelButtonStyle实现了自定义文本以及按钮样式。 例子参考固定样式弹框,如下图

时间滑动选择器弹窗 (TimePickerDialog)

开发者可根据24小时的时间区间,创建时间滑动选择器弹窗,将时间信息清晰地展示在弹出的窗口上。

时间滑动选择器弹窗通过UIContext中的showTimePickerDialog接口实现。

该示例通过配置disappearTextStyletextStyleselectedTextStyleacceptButtonStylecancelButtonStyle实现了自定义文本以及按钮样式。 例子参考固定样式弹框


    文本滑动选择器弹窗 (TextPickerDialog)

    开发者可根据指定的选择范围,创建文本滑动选择器弹窗,将文本信息清晰地展示在弹出的窗口上。

    文本滑动选择器弹窗通过UIContext中的showTextPickerDialog接口实现。

    示例中通过设置range的参数类型为TextCascadePickerRangeContent[],实现3列文本选择器弹窗。当按下确定按钮时,弹窗会通过onAccept返回目前所选中文本和索引值。如需弹窗再次弹出时显示选中的是上一次确定的文本,就要在回调中重新给select进行赋值。 例子参考固定样式弹框

    列表选择弹窗 (ActionSheet)

    列表选择器弹窗适用于呈现多个操作选项,尤其当界面中仅需展示操作列表而无其他内容时。

    列表选择器弹窗通过UIContext中的showActionSheet接口实现。

    列表选择弹窗中,title字段的字体最大放大倍数为2。

    该示例通过配置width、height、transition等接口,定义了弹窗的样式以及弹出动效。 例子参考固定样式弹框

    警告弹窗 (AlertDialog)

    向用户提问或得到用户的许可时,使用警告弹窗。

    • 警告弹窗用来提示重要信息,但会中断当前任务,尽量提供必要的信息和有用的操作。
    • 避免仅使用警告弹窗提供信息,用户不喜欢被信息丰富但不可操作的警告打断。

    警告弹窗通过UIContext中的showAlertDialog接口实现。

    警告弹窗中,title和subtitle字段的字体最大放大倍数为2。

    该示例通过配置width、height、transition等接口,定义了多个按钮弹窗的样式以及弹出动效。例子参考固定样式弹框

    不依赖UI组件的全局自定义弹框

    在广告、中奖、警告、软件更新等与用户交互响应操作的场景下,可以使用UIContext中获取到的PromptAction对象提供的openCustomDialog接口来实现自定义弹出框。相较于CustomDialogController优势点在于页面解耦,支持动态刷新

    说明

    弹出框(openCustomDialog)存在两种入参方式创建自定义弹出框:

    • openCustomDialog(传参为ComponentContent形式):通过ComponentContent封装内容可以与UI界面解耦,调用更加灵活,可以满足开发者的封装诉求。具有较高的灵活性,弹出框样式完全自定义,并且在弹出框打开后可以使用updateCustomDialog方法动态更新弹出框的参数。
    • openCustomDialog(传参为builder形式):相对于ComponentContent,builder必须要与上下文做绑定,与UI存在一定耦合。此方法有默认的弹出框样式,适合于开发者想要实现与系统弹窗默认风格一致的效果。

    本文介绍通过入参形式为ComponentContent创建自定义弹出框,传builder形式的弹出框使用方法可参考openCustomDialog

    弹出框(openCustomDialog)默认为模态弹窗且有蒙层,不可与蒙层下方控件进行交互(不支持点击和手势等向下透传)。可以通过配置promptAction.BaseDialogOptions类型中的isModal属性来实现模态和非模态弹窗,详细说明可参考弹窗的种类

    当isModal为true时,弹出框为模态弹窗,且弹窗周围的蒙层区不支持透传。isModal为false时,弹出框为非模态弹窗,且弹窗周围的蒙层区可以透传。因此如果需要同时允许弹出框的交互和弹出框外页面的交互行为,需要将弹出框设置为非模态。

    生命周期

    弹出框提供了生命周期函数用于通知用户该弹出框的生命周期。生命周期的触发时序依次为:onWillAppear -> onDidAppear -> onWillDisappear -> onDidDisappear。

    名称 类型 说明
    onDidAppear () => void 弹出框弹出后的事件回调。
    onDidDisappear () => void 弹出框消失后的事件回调。
    onWillAppear () => void 弹出框显示动效前的事件回调。
    onWillDisappear () => void 弹出框退出动效前的事件回调。

    接口概述

    创建并弹出自定义弹框接口及参数说明

    更新自定义弹框接口及参数说明

    对自定义弹窗示例代码的讲解参考视频课程16分钟处

    自定义弹出框的打开与关闭

    说明

    详细变量定义请参考完整示例

    1. 创建ComponentContent。

      ComponentContent用于定义自定义弹出框的内容。其中,wrapBuilder(buildText)封装自定义组件,new Params(this.message)是自定义组件的入参,可以缺省,也可以传入基础数据类型。

    2. 打开自定义弹出框。

      调用openCustomDialog接口打开的弹出框默认customStyle为true,即弹出框的内容样式完全按照contentNode自定义样式显示。

    3. 关闭自定义弹出框。

      由于closeCustomDialog接口需要传入待关闭弹出框对应的ComponentContent。因此,如果需要在弹出框中设置关闭方法,则可参考完整示例封装静态方法来实现。

      关闭弹出框之后若需要释放对应的ComponentContent,则需要调用ComponentContent的dispose方法。

    更新自定义弹出框的内容

    ComponentContent与BuilderNode有相同的使用限制,不支持自定义组件使用@Reusable@Link@Provide@Consume等装饰器,来同步弹出框弹出的页面与ComponentContent中自定义组件的状态。因此,若需要更新弹出框中自定义组件的内容可以通过ComponentContent提供的update方法来实现。

    更新自定义弹出框的属性

    通过updateCustomDialog可以动态更新弹出框的属性。目前支持更新弹出框的对齐方式、基于对齐方式的偏移量、是否点击蒙层自动关闭以及蒙层颜色,对应的属性分别为BaseDialogOptions中的alignment、offset、autoCancel和maskColor。

    更新属性时,未设置的属性会恢复为默认值。例如,初始设置{ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } },更新时设置{ alignment: DialogAlignment.Bottom },则初始设置的offset: { dx: 0, dy: 50 }不会保留,会恢复为默认值。

    为弹出框内容和蒙层设置不同的动画效果

    当弹出框出现时,内容与蒙层显示动效一致。若开发者希望为弹出框内容及蒙层设定不同动画效果,从API version 19开始,可通过BaseDialogOptions中dialogTransition和maskTransition属性单独配置弹窗内容与蒙层的动画。具体的动画效果请参考组件内转场 (transition)

    说明

    当isModal为true时,蒙层将显示,此时可以设置蒙层的动画效果;否则,maskTransition将不生效。

    设置弹出框避让软键盘的距离

    为显示弹出框的独立性,弹出框弹出时会与周边进行避让,包括状态栏、导航条以及键盘等留有间距。故当软键盘弹出时,默认情况下,弹出框会自动避开软键盘,并与之保持16vp的距离。从API version 15开始,开发者可以利用BaseDialogOptions中的keyboardAvoidMode和keyboardAvoidDistance这两个配置项,来设置弹出框在软键盘弹出时的行为,包括是否需要避开软键盘以及与软键盘之间的距离。

    设置软键盘间距时,需要将keyboardAvoidMode值设为KeyboardAvoidMode.DEFAULT。

    基于ArkUI实现多种样式弹框功能

    本篇Codelab主要介绍如何给应用添加各种类型的弹窗,弹窗主要包括气泡提示(Popup)、即时反馈(Toast)、固定样式弹出框、自定义弹窗等。帮助开发者了解各种弹窗的类型,并掌握对应的使用方法。

    相关概念

    各案例代码参考基于ArkUI实现多种样式弹框功能

    气泡提示(Popup)的实现

        Row() {
          Image($r('app.media.dot_grid'))
            .width(24)
            .height(24)
        }
        .onClick(() => {
          this.customPopup = !this.customPopup
        })
        .bindPopup(this.customPopup, {
          builder: this.PopupBuilder, // Bubble content
          placement: Placement.Bottom, // The pop position of the bubble
          onStateChange: (e) => {
            if (!e.isVisible) {
              this.customPopup = false;
            }
          }
        })

    即时反馈(Toast)的实现

      Row({ space: 2 }) {
        Text($r('app.string.save'))
          .fontSize(16)
          .opacity(0.9)
      }
      .width(200)
      .height(50)
      .padding(16)
      .onClick(() => {
        this.ctx.getPromptAction().showToast({
          message: $r('app.string.save_successfully'),
          duration: 2000
        })
      })

    固定样式弹出框的实现

    日期滑动选择器弹窗的实现

    this.getUIContext().showDatePickerDialog({
      start: new Date('1925-1-1'),
      end: new Date('2055-12-31'),
      selected: this.selectTime,
      lunarSwitch: true,
      showTime: false,
      onDateAccept: (value: Date) => {
        this.selectTime = value;
        let birthDateArray = JSON.stringify(value).slice(1, 11).split('-');
        let year = Number(birthDateArray[0]);
        let month = Number(birthDateArray[1]);
        let day = Number(birthDateArray[2]);
        this.birthDate = CommonUtils.getBirthDateValue(year, month, day);
      }
    })

    文本滑动选择器弹窗的实现

    this.getUIContext().showTextPickerDialog({
      range: this.sexArray,
      selected: this.select,
      canLoop: false,
      onAccept: (value: TextPickerResult) => {
        this.select = value.index as number;
        this.sex = value.value as string;
      },
      onChange: (value: TextPickerResult) => {
        this.select = value.index as number;
      }
    })

    自定义弹窗的实现

     代码参考基于ArkUI实现多种样式弹框功能

    Logo

    讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

    更多推荐