ArkUI框架之promptAction弹窗
弹窗
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 = 0build() {Column({ space: 10 }) {Button("打开自定义弹窗").onClick(() => {promptAction.openCustomDialog({builder: () => this.CustomDialogBuilder(),}).then((dialogId: number) => {this.customDialogId = dialogId})})}.height('100%').width('100%')}@BuilderCustomDialogBuilder() {CustomDialogComponent({ dialogId: this.customDialogId })}
}@Component
struct CustomDialogComponent {@Prop dialogId: numberbuild() {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 弹窗最佳实践
- 先封装弹窗内容和样式
@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)}
}
- 在需要使用弹窗的页面中使用@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%')}@BuilderDialogBuilder() {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 = componentContentPromptActionUtils.options = options ?? PromptActionUtils.optionsPromptActionUtils.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 = textthis.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, //是否为农历,默认为falselunarSwitch: false, //是否显示农历切换开关,默认为falseshowTime: false, //是否显示时间useMilitaryTime:true, //是否展示24小时制,默认为falseacceptButtonStyle:{ //确认按钮的样式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 = valueconsole.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 })}
}