弹窗和提示气泡是应用中与用户交互最频繁的组件之一,设计是否到位直接影响用户体验。在 HarmonyOS Next 中,ArkUI 框架提供了从系统级 AlertDialog 到完全自定义的 CustomDialog,再到轻量级 Popup 和全局 Toast 的完整解决方案。本文将从应用场景出发,系统梳理各类弹框和提示气泡的实现方式、核心配置和选型建议。


一、弹框体系概览

HarmonyOS Next 的弹框提示体系可以分为三个层级,每个层级服务不同的交互场景:

分类 典型组件 适用场景
系统预置弹框 AlertDialog 操作确认、警告提示、简单选择
自定义弹框 @CustomDialog + CustomDialogController 包含表单输入、自定义布局、复杂交互
轻量提示 Toast / bindPopup 操作反馈、引导提示、补充信息

此外,还有 OverlayManager(浮层)、bindSheet(半模态页面)和 bindContentCover(全模态页面)等更高级的 UI 呈现方式,适用于需要独立页面级交互的场景。


二、AlertDialog:系统级警告弹窗

AlertDialog 是最常用的预置弹窗,适合快速实现确认/取消类交互。通过 AlertDialog.show() 静态方法调用,无需提前声明组件。

基础用法

以下是一个删除确认弹窗的示例:

typescript

@Entry
@Component
struct AlertDialogPage {
  @State dialogMessage: string = ''

  build() {
    Column({ space: 10 }) {
      Button('删除联系人').onClick(() => {
        AlertDialog.show({
          title: '删除联系人',
          message: '是否删除所选的联系人?',
          primaryButton: {
            value: '取消',
            action: () => {
              this.dialogMessage = '已取消删除'
            }
          },
          secondaryButton: {
            value: '删除',
            fontColor: Color.Red,
            action: () => {
              // 执行删除逻辑
              this.dialogMessage = '删除成功'
            }
          }
        })
      })
      Text('操作结果:' + this.dialogMessage)
    }
    .height('100%')
    .width('100%')
  }
}

核心配置参数

AlertDialog.show() 支持丰富的配置项,满足大多数场景需求:

参数 类型 说明
title string 弹窗标题
subtitle string 副标题
message string 弹窗内容
autoCancel boolean 点击遮障层是否自动关闭,默认 true
alignment DialogAlignment 垂直对齐方式,默认居中
gridCount number 弹窗宽度占栅格数,默认 4
cornerRadius Dimension 圆角半径,默认 32vp
backgroundBlurStyle BlurStyle 背景模糊材质
onWillDismiss () => void 交互式关闭回调

primaryButton 和 secondaryButton 支持配置按钮文字、颜色和点击回调,是操作确认类弹窗的核心配置。


三、@CustomDialog:自定义弹框

当系统预置弹窗无法满足需求时(如需要表单输入、定制布局、复杂交互),可以使用 @CustomDialog 装饰器构建完全自定义的弹窗。

1. 定义自定义弹窗组件

使用 @CustomDialog 装饰器声明自定义弹窗,内部必须声明 CustomDialogController 类型的控制器属性,外部通过该控制器控制弹窗的打开和关闭。

typescript

// components/CustomInputDialog.ets
@CustomDialog
export struct CustomInputDialog {
  @State inputValue: string = ''
  dialogController?: CustomDialogController
  
  // 外部传入的回调
  cancel?: () => void
  confirm?: (value: string) => void

  build() {
    Column() {
      Text('请输入昵称')
        .fontSize(18)
        .width('100%')
        .textAlign(TextAlign.Center)
        .margin({ top: 30 })

      TextInput({ 
        text: $$this.inputValue, 
        placeholder: '请输入昵称' 
      })
        .height(40)
        .margin(10)
        .fontSize(18)

      Row() {
        Button('取消')
          .layoutWeight(1)
          .margin(5)
          .backgroundColor(Color.Gray)
          .onClick(() => {
            this.dialogController?.close()
            this.cancel?.()
          })

        Button('确定')
          .layoutWeight(1)
          .margin(5)
          .onClick(() => {
            this.dialogController?.close()
            this.confirm?.(this.inputValue)
          })
      }
      .padding(10)
      .margin({ bottom: 10 })
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(16)
  }
}

2. 在页面中使用自定义弹窗

页面中需要创建 CustomDialogController 实例,传入自定义弹窗组件并配置相关参数:

typescript

// pages/ProfilePage.ets
import { CustomInputDialog } from '../components/CustomInputDialog'

@Entry
@Component
struct ProfilePage {
  @State nickName: string = '默认昵称'

  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomInputDialog({
      cancel: () => {
        console.info('用户取消输入')
      },
      confirm: (value: string) => {
        this.nickName = value
        console.info('新昵称:' + value)
      }
    }),
    alignment: DialogAlignment.Center,  // 居中显示
    customStyle: false,                 // 使用默认样式
    autoCancel: true,                   // 点击遮障层可关闭
    maskColor: 0x33000000               // 半透明遮罩
  })

  build() {
    Column({ space: 20 }) {
      Text('当前昵称:' + this.nickName)
        .fontSize(18)

      Button('修改昵称')
        .onClick(() => {
          this.dialogController.open()
        })
    }
    .height('100%')
    .width('100%')
  }
}

3. CustomDialogController 核心配置

参数 类型 说明
builder CustomBuilder 自定义弹窗内容构造器(必填)
alignment DialogAlignment 对齐方式,默认居中
offset { dx, dy } 偏移量
customStyle boolean 是否自定义容器样式
autoCancel boolean 点击遮障层是否关闭
maskColor string 遮罩颜色,默认 0x33000000
openAnimation AnimationOptions 打开动画
closeAnimation AnimationOptions 关闭动画
onWillDismiss () => void 关闭前回调

@CustomDialog 提供了极高的灵活性,广告弹窗、协议确认、信息填写等场景都能优雅实现。


四、Popup:轻量级提示气泡

Popup(气泡提示)用于在组件附近显示补充信息或操作入口,特点是轻量、不打断当前操作流程。

使用 bindPopup 绑定气泡

通过 bindPopup 方法将气泡绑定到某个组件上,通过状态变量控制显示/隐藏。

typescript

@Entry
@Component
struct PopupExample {
  @State showPopup: boolean = false

  @Builder popupBuilder() {
    Row({ space: 8 }) {
      Image($r('app.media.icon'))
        .width(24)
        .height(24)
      Text('这是自定义气泡提示')
        .fontSize(14)
    }
    .padding(12)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .shadow({ radius: 8, color: 0x33000000 })
  }

  build() {
    Column({ space: 30 }) {
      // 方式一:使用默认样式(PopupOptions)
      Button('默认气泡')
        .onClick(() => {
          this.showPopup = !this.showPopup
        })
        .bindPopup(this.showPopup, {
          message: '这是一条气泡提示消息',
          placementOnTop: false,
          primaryButton: {
            value: '知道了',
            action: () => {
              this.showPopup = false
            }
          },
          onStateChange: (e) => {
            if (!e.isVisible) {
              this.showPopup = false
            }
          }
        })

      // 方式二:使用自定义内容(CustomPopupOptions)
      Button('自定义气泡')
        .onClick(() => {
          this.showPopup = !this.showPopup
        })
        .bindPopup(this.showPopup, {
          builder: this.popupBuilder,
          placement: Placement.Top,      // 气泡在按钮上方
          enableArrow: true,             // 显示指向箭头
          popupColor: Color.White,
          mask: { color: 0x22000000 },   // 半透明遮罩
          onStateChange: (e) => {
            if (!e.isVisible) {
              this.showPopup = false
            }
          }
        })
    }
    .width('100%')
    .padding(50)
  }
}

Popup 核心配置

参数 类型 说明
message string 气泡文字内容(PopupOptions)
builder CustomBuilder 自定义气泡布局(CustomPopupOptions)
placement Placement 显示位置,默认 Bottom
enableArrow boolean 是否显示指向箭头
popupColor Color 气泡背景色
mask { color } 遮罩配置
showInSubWindow boolean 是否显示在子窗口
onStateChange (e) => void 显示/隐藏状态变化回调

Popup 非常适合功能引导、提示说明、快捷操作菜单等场景。


五、进阶:浮层(Overlay)与模态页面

对于更复杂的场景,HarmonyOS Next 还提供了 OverlayManager(浮层)、bindSheet(半模态页面)和 bindContentCover(全模态页面)。

  • OverlayManager:在页面之上添加独立浮层,与页面生命周期解耦,适合活动入口、悬浮按钮等场景。通过 UIContext 获取 OverlayManager 实例进行添加/删除操作。

  • bindSheet:在组件上绑定半模态页面,下方页面保持可见,适合设置项确认、选择器等场景。

  • bindContentCover:全屏模态覆盖,适合需要完整页面级交互的场景(如表单填写、详情查看)。


六、选型建议

场景 推荐方案 原因
简单确认/警告 AlertDialog 一行代码调用,快速实现
带输入框的表单弹窗 @CustomDialog 完全自定义,支持任意复杂布局
操作引导/补充信息 Popup 轻量级,不打断操作流程
活动入口/悬浮元素 OverlayManager 与页面解耦,生命周期独立
设置项确认、选择器 bindSheet 半模态,保留上下文可见
独立页面级交互 bindContentCover 全屏覆盖,类似新页面

七、注意事项

  1. 弹窗层级管理:多个弹窗叠加时,后打开的会覆盖在先打开的之上,注意控制弹窗的打开和关闭逻辑,避免堆叠混乱。

  2. 自定义弹窗的控制器生命周期CustomDialogController 应在页面组件中声明,不要在 build 方法内创建,否则会导致重复实例化和状态丢失。

  3. autoCancel 与 onWillDismiss 配合:需要拦截关闭操作时,使用 onWillDismiss 回调,并在回调中决定是否真正关闭。

  4. 跨设备适配:弹窗的宽度、高度建议使用相对单位(vp、百分比),并结合 gridCount 等属性适配不同屏幕尺寸。

  5. 性能考虑:自定义弹窗的 builder 内容应尽量精简,避免在弹窗内部执行耗时操作,确保打开和关闭动画流畅。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐