自定义弹窗选型
合理选择不同的系统能力实现弹窗,有利于提升应用开发效率,实现更好的功能需求,因此了解自定义弹窗的选型和差异非常重要。在应用开发中,为了选择出合适的弹窗选型,从使用场景上,需要重点关注以下两点:
- 弹窗与界面代码解耦
在开发业务逻辑时,例如遇到一些网络请求失败的场景,需要触发相应的弹窗提醒用户进行操作,由于在任何页面都有可能触发对应的弹窗,此时弹窗不是与某个页面相关联,这个情况下,就需要弹窗与界面的解耦。
- 弹窗在界面跳转后保留
在一些权限配置页,用户首次进入应用时会弹出权限配置弹窗,让用户进行操作,此时若点击跳转到隐私详情页面,返回后弹窗需要保留在页面上。
系统提供了四种不同的方式来实现自定义弹窗,分别是CustomDialog、promptAction、UIContext.getPromptAction、Navigation.Dialog,在开发业务时,需要结合每种弹窗的特点来选择弹窗。
- CustomDialog弹窗,必须在@Component struct内部定义,即在UI层创建控制器,当一个页面需要弹出多个自定义弹窗时,就需要创建对应个数的CustomDialogController,这会造成UI层代码冗余,无法做到弹窗与界面的解耦。
- promptAction弹窗,为了解决CustomDialog弹窗的问题,支持了UI元素复用机制@Builder,但依赖UI组件。
- UIContext.getPromptAction弹窗,基于promptAction弹窗演进而来,支持全局自定义弹窗,不依赖UI组件,依赖UIContext,支持在非页面文件中使用,弹窗内容支持动态修改,支持自定义弹窗圆角半径、大小和位置,适合在与页面解耦的全局弹窗、自定义弹窗显示和退出动画等场景下使用。
- Navigation.Dialog弹窗,基于Navigation路由形式,以Component组件页面存在于路由栈中,以进出栈的方式打开或关闭弹窗,可以实现弹窗与UI界面解耦,默认透明显示,适合在切换页面弹窗不消失场景下使用。
总结如下:
使用示例如下:
一、CustomerDialog
1、定义:
// 自定义提示弹框 // @CustomerDialog @CustomDialog export struct TipDialog {@State title: string = "提示" // 标题@State message: string = ""; // 提示内容@State cancelValue: string = "取消"; //取消按钮文案@State confirmValue: string = "确定"; //确定按钮文案cancel?: () => void // 取消事件confirm?: () => void // 确定事件controller: CustomDialogController = new CustomDialogController({builder: TipDialog()})build() {Column() {Text(this.title).width('100%').height(40).textAlign(TextAlign.Center).fontColor(Color.White).backgroundColor($r('app.color.dialog_title_bg')).borderRadius({ topLeft: 10, topRight: 10 })Text(this.message).height(70).width('100%').textAlign(TextAlign.Center).backgroundColor(Color.White)Row() {Text(this.cancelValue).layoutWeight(1).backgroundColor(Color.White).fontColor(Color.Black).textAlign(TextAlign.Center).height(40).borderRadius({ bottomLeft: 10 }).onClick(() => {if (this.cancel) {this.cancel()}})Text(this.confirmValue).layoutWeight(1).backgroundColor($r('app.color.main_color')).fontColor(Color.White).textAlign(TextAlign.Center).height(40).borderRadius({ bottomRight: 10 }).onClick(() => {if (this.confirm) {this.confirm()}})}}.width('100%')} }
2、使用
import {TipDialog} from '../../components/dialogs/TipDialog'@Entry @Component struct More {// 有多少个弹框,就需要定义多少个CustomDialogController// 造成UI层代码冗余,无法做到弹窗与界面的解耦。controller:CustomDialogController= new CustomDialogController({builder : TipDialog({message: '点击了内容',confirm: ()=>{console.log('点击了确定')this.controller.close()},cancel: ()=>{console.log('点击了取消')this.controller.close()}}),alignment: DialogAlignment.Center,offset: { dx: 0, dy: -20 },customStyle: false,width:'80%',cornerRadius:10,backgroundColor: 0xd9ffffff,})showDialog(){this.controller.open()}build() {Row() {Column() {Button('打开弹框').fontWeight(FontWeight.Bold).onClick(()=>{this.showDialog()})}.width('100%')}.height('100%')} }
二、UIContext.getPromptAction弹窗
1、定义
// 自定义弹框组件 // 使用UIContext.getPromptAction.openCustomDialog的方式 // https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-custome-dialog-development-practice-V5#section7466312192919 // https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-arkui-uicontext-V5#opencustomdialog12// 弹框可设置参数 export class DialogParms{public title: string = "提示" // 标题public message: string = "" // 提示内容public cancelValue: string = "取消" // 取消按钮文案public confirmValue: string = "确定" // 确定按钮文案public cancel?: (() => void) | undefined // 取消事件public confirm?: (() => void) | undefined // 确定事件public setTitle(value: string):void {this.title = value}public setMessage(value: string):void {this.message = value}public setCancelValue(value: string):void {this.cancelValue = value}public setConfirmValue(value: string):void {this.confirmValue = value}public setCancel(value: (() => void) | undefined){this.cancel = value}public setConfirm(value: (() => void) | undefined) {this.confirm = value}constructor(title:string) {this.title = title}}// 全局自定义函数 @Builder export function WarmDialog(parms:DialogParms){Column() {Text(parms.title).width('100%').height(40).textAlign(TextAlign.Center).fontColor(Color.White).backgroundColor($r('app.color.dialog_title_bg')).borderRadius({topLeft:10,topRight:10})Text(parms.message).height(70).width('100%').textAlign(TextAlign.Center).backgroundColor(Color.White)Row() {Text(parms.cancelValue).layoutWeight(1).backgroundColor(Color.White).fontColor(Color.Black).textAlign(TextAlign.Center).height(40).borderRadius({bottomLeft:10}).onClick(()=>{if (parms.cancel) {parms.cancel()}})Text(parms.confirmValue).layoutWeight(1).backgroundColor($r('app.color.main_color')).fontColor(Color.White).textAlign(TextAlign.Center).height(40).borderRadius({bottomRight:10}).onClick(()=>{if (parms.confirm) {parms.confirm()}})}}.width('80%') }
2、使用
import { ComponentContent, PromptAction, UIContext } from '@kit.ArkUI'; import {WarmDialog,DialogParms} from '../../components/dialogs/WarmDialog' @Entry @Component struct More {uiContext:UIContext = this.getUIContext()showDialog(){let promptAction:PromptAction = this.uiContext.getPromptAction()let dialogParms = new DialogParms("警告")dialogParms.setTitle("警告")dialogParms.setMessage("这是警告内容")dialogParms.setCancel(()=>{promptAction.closeCustomDialog(builderView)console.log('点击了取消')})dialogParms.setConfirm(()=>{promptAction.closeCustomDialog(builderView)console.log('点击了确定')})let builderView = new ComponentContent(this.uiContext,wrapBuilder(WarmDialog),dialogParms)promptAction.openCustomDialog(builderView,{alignment:DialogAlignment.Center},)}build() {Row() {Column() {Button('打开弹框').fontWeight(FontWeight.Bold).onClick(()=>{this.showDialog()})}.width('100%')}.height('100%')} }