ArkUI框架之promptAction弹窗

发布于:2025-08-30 ⋅ 阅读:(16) ⋅ 点赞:(0)

弹窗

1.弹窗概述

弹窗是应用开发需要实现的基础功能,通常用来展示用户当前需要或用户必须关注的信息或操作,可用于广告、中奖、警告、软件更新等与用户交互响应的操作。系统提供了四种不同的方式来实现自定义弹窗,分别是CustomDialog、promptAction、UIContext.getPromptAction、Navigation.Dialog,在开发业务时,需要结合每种弹窗的特点来选择弹窗。

2. promptAction 弹窗

API version 9开始推出promptAction弹窗,支持了UI元素复用机制@Builder,但依赖UI组件。

2.1 导入模块

import { promptAction } from '@kit.ArkUI';

2.2 Toast弹窗

Toast弹窗是一种文本提示框;
在这里插入图片描述

Button("弹出Toast").onClick(() => {
  promptAction.showToast({ message: "我是吐司🍞" })
})

2.3 自定义弹窗

通过promptAction.openCustomDialog打开自定义弹窗,弹窗宽度在设备竖屏时默认为所在窗口宽度 - 左右margin(16vp,设备为2in1时为40vp),最大默认宽度为400vp。
在这里插入图片描述
promptAction.openCustomDialog打开后,返回Promise表示弹窗的id,关闭弹窗时使用。

import { promptAction } from '@kit.ArkUI'


@Entry
@Component
struct Index {
  @State customDialogId: number = 0
  build() {
    Column({ space: 10 }) {
      Button("打开自定义弹窗")
        .onClick(() => {
          promptAction.openCustomDialog({
            builder: () => this.CustomDialogBuilder(),
          }).then((dialogId: number) => {
            this.customDialogId = dialogId
          })
        })
    }
    .height('100%')
    .width('100%')
  }

  @Builder
  CustomDialogBuilder() {
    CustomDialogComponent({ dialogId: this.customDialogId })
  }
}

@Component
struct CustomDialogComponent {
  @Prop dialogId: number

  build() {
    Column() {
      Text("我是自定义弹窗")
      Row() {
        Button("取消").onClick(() => {
          promptAction.closeCustomDialog(this.dialogId)
          console.log("点击了取消按钮")
        })
        Button("确定").onClick(() => {
          promptAction.closeCustomDialog(this.dialogId)
          console.log("点击了确定按钮")
        })
      }
    }
  }
}

2.4 弹窗样式

通过promptAction.openCustomDialog打开弹窗,在指定弹窗UI的同时可以自定义样式,如:弹窗宽、高、背景、边框、蒙层、对齐方式、阴影等。
在这里插入图片描述

Button("打开自定义弹窗")
    .onClick(() => {
      promptAction.openCustomDialog({
        builder: () => this.CustomDialogBuilder(),
        keyboardAvoidMode: KeyboardAvoidMode.DEFAULT, //是否避让软键盘(DEFAULT避让,NONE不避让)
        autoCancel:false,   //点击遮罩层不自动关闭
        alignment:DialogAlignment.Bottom,  //对齐方式
        backgroundColor:Color.White,
        offset: { dx: 5, dy:0 }, //偏移量
        isModal:false,  //是否为模态窗口(true有蒙层,false无蒙层)
        maskColor:"#ddeedd",  //蒙层颜色
        cornerRadius: 20,   //圆角
        width: '80%',   //宽度
        height: 100,    //高度
        borderWidth: 2, //边框宽度
        borderStyle: BorderStyle.Dashed, //边框样式
        borderColor: Color.Blue,  //边框颜色
        shadow: {    //阴影
          radius: 50,   //圆角
          color: Color.Green, //颜色
          offsetX: 30,      //向右偏移
          offsetY: -30      //向下偏移
        },
      }).then((dialogId: number) => {
        this.customDialogId = dialogId
      })
    })

2.5 弹窗最佳实践

在这里插入图片描述

  1. 先封装弹窗内容和样式
@Component
export struct DialogComponent {
  build() {
    Column() {
      Text("🚀这是一个对话框")
        .fontSize(20)

      Button('确定')
        .onClick(() => {
          let dialogId = AppStorage.get<number>('dialogId');
          promptAction.closeCustomDialog(dialogId) 
        })
    }
    .width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center)
  }
}
  1. 在需要使用弹窗的页面中使用@Builder引入弹窗组件。
import { promptAction } from "@kit.ArkUI"

@Entry
@Component
struct UIContextPromptActionDialogPage {
  build() {
    Column() {
      Button('打开弹窗')
        .onClick(() => {
          promptAction.openCustomDialog({
            builder: () => this.DialogBuilder(),
            alignment: DialogAlignment.Center,
            height:200,
            maskColor: 'rgba(0, 0, 0, 0.2)',
          }).then((dialogId: number) => {
            AppStorage.setOrCreate('dialogId', dialogId);
          })
        })
    }
    .height('100%')
    .width('100%')
  }

  @Builder
  DialogBuilder() {
    DialogComponent()
  }
}

3. UIContext.getPromptAction 弹窗

UIContext.getPromptAction()弹窗,基于promptAction弹窗演进而来,支持全局自定义弹窗,不依赖UI组件,依赖UIContext,支持在非页面文件中使用,弹窗内容支持动态修改,支持自定义弹窗圆角半径、大小和位置,适合在与页面解耦的全局弹窗、自定义弹窗显示和退出动画等场景下使用。
在这里插入图片描述

3.1 快速入门

import { ComponentContent, PromptAction, UIContext } from '@kit.ArkUI';

//UI上下文的对象(你可以理解为是一个管理UI的工具箱,它提供了很多函数可以对UI进行操作,如弹窗、动画等)
let ctx: UIContext | undefined = undefined
//弹窗内容
let componentContent: ComponentContent<Object> | undefined = undefined
//PromptAction提供了多种函数用于控制弹窗的显示、隐藏、更新
let promptAction: PromptAction | undefined = undefined

@Entry
@Component
struct Index {

  aboutToAppear(): void {
    ctx = this.getUIContext()
    componentContent = new ComponentContent(
      ctx,
      wrapBuilder(buildText),
      "HarmonyOS"
    );
    promptAction = ctx.getPromptAction()
  }

  build() {
    Row() {
      Column() {
        Button("打开弹窗")
          .margin({ top: 50 })
          .onClick(() => {
            //打开弹窗
            promptAction?.openCustomDialog(
              componentContent,
              {
                alignment: DialogAlignment.Center, //弹窗的位置
                offset: {
                  //弹窗的偏移量
                  dx: 0,
                  dy: 50
                }
              })
          })
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
  }
}

@Builder
function buildText(text: string) {
  Column() {
    Text(text)
      .fontSize(50)
      .fontWeight(FontWeight.Bold)
      .margin({ bottom: 36 })
    Button("关闭").onClick(() => {
      promptAction?.closeCustomDialog(componentContent)
    })
  }.backgroundColor(Color.White)
  .borderRadius(10)
  .padding(10)
}

3.2 封装弹窗参数

通过上面的快速入门案例我们发现,UIContext.getPromptAction弹窗依赖三个参数,分别是UIContext、ComponentContent、promptAction.BaseDialogOptions,我们可以使用一个类来封装这三个参数,方便在任何位置进行弹窗操作。

import { promptAction } from '@kit.ArkUI';

//单独写一个控制窗体打开与关闭的工具类
export class PromptActionUtils {
  private static uicontext: UIContext //窗体的上下文(窗体的持有者)
  private static componentContent: ComponentContent<Object> //代表窗体的UI和数据
  private static options: promptAction.BaseDialogOptions //窗体的UI样式

  public static setContext(context: UIContext) {
    PromptActionUtils.uicontext = context;
  }

  public static setComponentContent(componentContent: ComponentContent<Object>) {
    PromptActionUtils.componentContent = componentContent;
  }

  public static setOptions(options: promptAction.BaseDialogOptions) {
    PromptActionUtils.options = options;
  }

  //打开弹窗
  public static openDialog() {
    if (PromptActionUtils.componentContent != null) {
      if (PromptActionUtils.options) {
        PromptActionUtils.uicontext.getPromptAction()
          .openCustomDialog(PromptActionUtils.componentContent, PromptActionUtils.options)

      } else {
        PromptActionUtils.uicontext.getPromptAction()
          .openCustomDialog(PromptActionUtils.componentContent)
      }
    }
  }

  //关闭弹窗
  public static closeDialog() {
    if (PromptActionUtils.componentContent != null) {
      PromptActionUtils.uicontext.getPromptAction().closeCustomDialog(PromptActionUtils.componentContent)
    }
  } 

  //更新弹窗
  public static updateDialog(componentContent: ComponentContent<Object>, options?: promptAction.BaseDialogOptions) {
    if (componentContent != null && options !== null) {
      PromptActionUtils.componentContent = componentContent
      PromptActionUtils.options = options ?? PromptActionUtils.options
      PromptActionUtils.uicontext.getPromptAction()
        .updateCustomDialog(PromptActionUtils.componentContent, PromptActionUtils.options)
    }
  }
}

3.3 自定义弹窗

在这里插入图片描述

@Entry
@Component
struct PromptActionPage {
  // 在页面显示的时候对窗体UI、数据、样式出初始化
  paramOptions = new ParamOptions("李四王五赵六", 30)

  aboutToAppear(): void {
    console.log("学习学习学习学习学习学习学习")
    PromptActionUtils.setContext(this.getUIContext())
    PromptActionUtils.setComponentContent(new ComponentContent(this.getUIContext(), wrapBuilder(MyDialog),
      this.paramOptions))
    PromptActionUtils.setOptions({
      isModal: true, //是否有蒙板
      alignment: DialogAlignment.Center  //窗体位置
    })
  }

  build() {
    Column() {
      Button("弹窗")
        .onClick(() => {
          PromptActionUtils.openDialog()
          // setTimeout(()=>{
          //   console.log("更新弹窗")
          //   PromptActionUtils.updateDialog({alignment:DialogAlignment.BottomEnd})
          // },2000)

        })

      Button("更新")
        .onClick(() => {
          //this.paramOptions = new ParamOptions("哈哈哈哈",50)
          PromptActionUtils.updateDialog(
            new ComponentContent(this.getUIContext(), wrapBuilder(MyDialog), new ParamOptions("看看坎坎坷坷", 50)),
            {alignment:DialogAlignment.Bottom}
          )
        })
    }
    .height('100%')
    .width('100%')
  }
}

//配置弹窗的数据
class ParamOptions {
  text: string //文本
  size: number //大小

  constructor(text: string //文本
    , size: number //文本大小
  ) {
    this.text = text
    this.size = size
  }
}

@Builder
function MyDialog(param: ParamOptions) {
  Column() {
    Text(`${param.text}`)
      .fontSize(`${param.size}`)

    Button("关闭")
      .onClick(() => {
        PromptActionUtils.closeDialog()
      })
  }.width(300)
  .height(200)
  .backgroundColor(Color.White)
  .borderRadius(10)
}

4.固定样式弹窗

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

4.1 菜单弹窗

在这里插入图片描述

import {promptAction} from '@kit.ArkUI';

@Entry
@Component
struct Index {
  @State city: string = ''
  buttons: [promptAction.Button, promptAction.Button?, promptAction.Button?, promptAction.Button?, promptAction.Button?, promptAction.Button?] =
    [
      {
        text: 'item1',
        color: '#666666'
      },
      {
        text: 'item2',
        color: '#000000'
      },
      {
        text: 'item3',
        color: '#000000'
      },
    ]

  build() {
    Column() {
      Button("菜单弹窗")
        .onClick(() => {
          try {
            promptAction.showActionMenu({
              title: '菜单弹窗标题',
              buttons: this.buttons
            })
              .then(data => {
                console.info('菜单弹窗显示成功: ' + data.index);
                this.city = this.buttons[data.index]?.text as string
              })
              .catch((err: Error) => {
                console.error('showActionMenu error: ' + err);
              })
          } catch (error) {

          }
        })
      Text(`${this.city}`)
    }
    .height('100%')
    .width('100%')
  }
}

4.2 普通对话框

在这里插入图片描述

import { promptAction } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  build() {
    Column() {
      Button("普通对话框")
        .onClick(() => {
          try {
            promptAction.showDialog({
              title: '普通对话框',
              message:"这是一个普通的对话框",
              buttons: [
                {
                  text:"取消",
                  color:"#000000"
                },
                {
                  text:'确认',
                  color:"#000000"
                }
              ]
            })
              .then(data => {
                if (data.index===0) {
                  promptAction.showToast({message:"点取消了"})
                }else if (data.index ===1){
                  promptAction.showToast({message:"点确定了"}) 
                }
              })
              .catch((err:Error) => {
                console.error('showDialog error: ' + err);
              })
          } catch (error) {

          }
        })
    }
    .height('100%')
    .width('100%')
  }
}

4.3 日历选择器

在这里插入图片描述

// xxx.ets
@Entry
@Component
struct CalendarPickerDialogExample {
  private selectedDate: Date = new Date()

  build() {
    Column() {
      Button("日历选择器")
        .onClick(() => {
          CalendarPickerDialog.show({
            selected: this.selectedDate,  //当前选中的日期
            acceptButtonStyle: {      //确定按钮样式
              fontColor: '#2787d9',
              fontSize: '16fp',
              backgroundColor: '#f7f7f7',
              borderRadius: 10
            },
            cancelButtonStyle: {     //取消按钮样式
              fontColor: Color.Red,
              fontSize: '16fp',
              backgroundColor: '#f7f7f7',
              borderRadius: 10
            },
            onAccept: (date: Date)=>{
              console.log("点击确认按钮")
              // 当弹出框再次弹出时显示选中的是上一次确定的日期
              this.selectedDate = date
            },
            onCancel: ()=>{
              console.log("点击取消按钮")
            },
            onChange:(date:Date)=>{
              console.log("当前日期是:"+date.toLocaleDateString())
            }
          })
        })
    }.width('100%')
    .height("100%")
  }
}

4.4 日期滑动选择器

在这里插入图片描述

@Entry
@Component
struct DatePickerDialogExample {
  @State selectTime: Date = new Date('2023-12-25T08:30:00');

  build() {
    Column() {
      Button('日期滑动选择器')
        .margin(30)
        .onClick(() => {
          this.getUIContext().showDatePickerDialog({
            start: new Date("1969-1-1"),  //开始日期
            end: new Date("2100-12-31"),  //结束日期
            selected: this.selectTime,  //选中的日期
            lunar:false,  //是否为农历,默认为false
            lunarSwitch: false, //是否显示农历切换开关,默认为false
            showTime: false, //是否显示时间
            useMilitaryTime:true, //是否展示24小时制,默认为false
            acceptButtonStyle:{     //确认按钮的样式
              fontColor:Color.Black,
              fontSize:12,
              fontWeight:FontWeight.Bold,
              backgroundColor:Color.Orange
            },
            cancelButtonStyle:{   //取消按钮的样式
              fontColor:Color.Black,
              fontSize:12,
              fontWeight:FontWeight.Lighter,
              backgroundColor:Color.Orange
            },
            onDateAccept: (value: Date) => {    //点击确定按钮时触发
              this.selectTime = value
              console.info("DatePickerDialog:onAccept()" + JSON.stringify(value))
            },
          })
        })
    }.width('100%').margin({ top: 5 })
  }
}

4.5 时间滑动选择器

在这里插入图片描述

// xxx.ets

@Entry
@Component
struct TimePickerDialogExample {
  @State selectTime: Date = new Date('2023-12-25T08:30:00');

  build() {
    Column() {
      Button('时间滑动选择器')
        .margin(30)
        .onClick(() => {
          this.getUIContext().showTimePickerDialog({
            selected: this.selectTime,  //选中的时间
            textStyle: {                //设置所有选项中最上和最下两个选项的文本颜色、字号、字体粗细。
              color: '#2787d9',
              font: {
                size: '14fp',
                weight: FontWeight.Normal
              }
            },
            disappearTextStyle:{       //设置所有选项中最上和最下两个选项的文本颜色、字号、字体粗细。
              color: '#dedede',
              font: {
                size: '16fp',
                weight: FontWeight.Normal
              }
            },
            selectedTextStyle: {      //设置选中项的文本颜色、字号、字体粗细。
              color: '#004aaf',
              font: {
                size: '20fp',
                weight: FontWeight.Bold
              }
            },
            useMilitaryTime:true, //是否24小时制
            acceptButtonStyle: {
              fontColor: '#2787d9',
              fontSize: '16fp',
              backgroundColor: '#f7f7f7',
              borderRadius: 10
            },
            cancelButtonStyle: {
              fontColor: Color.Red,
              fontSize: '16fp',
              backgroundColor: '#f7f7f7',
              borderRadius: 10
            },
            onAccept:(value:TimePickerResult)=>{
              console.log("当前选中的时间为:"+value.hour+"时"+value.minute+"分")
            }
          })
        })
    }.width('100%').margin({ top: 5 })
  }
}

4.6 文本滑动选择器

在这里插入图片描述

import { JSON } from '@kit.ArkTS';

@Entry
@Component
struct TextPickerDialogExample {
  private fruits: TextCascadePickerRangeContent[] = [
    {
      text: '辽宁省',
      children: [
        { text: '沈阳市', children: [{ text: '沈河区' }, { text: '和平区' }, { text: '浑南区' }] },
        { text: '大连市', children: [{ text: '中山区' }, { text: '金州区' }, { text: '长海县' }] }
      ]
    },
    {
      text: '吉林省',
      children: [
        { text: '长春市', children: [{ text: '南关区' }, { text: '宽城区' }, { text: '朝阳区' }] },
        { text: '四平市', children: [{ text: '铁西区' }, { text: '铁东区' }, { text: '梨树县' }] }
      ]
    },
    {
      text: '黑龙江省',
      children: [
        { text: '哈尔滨市', children: [{ text: '道里区' }, { text: '道外区' }, { text: '南岗区' }] },
        { text: '牡丹江市', children: [{ text: '东安区' }, { text: '西安区' }, { text: '爱民区' }] }
      ]
    }
  ]
  private select: number = 0; 

  build() {
    Column() {
      Button('文本滑动选择器')
        .margin(30)
        .onClick(() => {
          this.getUIContext().showTextPickerDialog({
            range: this.fruits,
            selected: this.select,
            onAccept: (result: TextPickerResult) => {
              console.log(result.value[0]+result.value[1]+result.value[2])
            }
          })
        })
    }.width('100%').margin({ top: 5 })
  }
}

网站公告

今日签到

点亮在社区的每一天
去签到