自定义弹窗选型
合理选择不同的系统能力实现弹窗,有利于提升应用开发效率,实现更好的功能需求,因此了解自定义弹窗的选型和差异非常重要。在应用开发中,为了选择出合适的弹窗选型,从使用场景上,需要重点关注以下两点:
-
弹窗与界面代码解耦
在开发业务逻辑时,例如遇到一些网络请求失败的场景,需要触发相应的弹窗提醒用户进行操作,由于在任何页面都有可能触发对应的弹窗,此时弹窗不是与某个页面相关联,这个情况下,就需要弹窗与界面的解耦。
-
弹窗在界面跳转后保留
在一些权限配置页,用户首次进入应用时会弹出权限配置弹窗,让用户进行操作,此时若点击跳转到隐私详情页面,返回后弹窗需要保留在页面上。
从能力角度,系统提供了四种不同的方式来实现自定义弹窗,分别是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界面解耦,默认透明显示,适合在切换页面弹窗不消失场景下使用。
上述四种弹窗的使用区别,可以从是否支持弹窗与界面代码解耦、弹窗在界面跳转后是否保留这两个方面去进行对比,总结如下:
CustomDialog | promptAction | UIContext.getPromptAction | Navigation.Dialog | |
---|---|---|---|---|
弹窗与界面代码解耦 | 不支持 | 不支持 | 支持 | 支持 |
弹窗在界面跳转后保留 | 否 | 否 | 否 | 是 |
在对解耦要求不高的情况下,可以使用上面CustomDialog、promptAction两个弹窗,本文围绕开发时主要常见的场景和问题,介绍UIContext.getPromptAction、Navigation.Dialog两个弹窗的使用。
用鸿蒙showCustomMsg提示框(标题和内容无法设置样式居中,总结就是一个字:丑!)
static showCustomMsg(title: string, content: string | Resource, confirmBtn?: string, cancelBtn?: string,confirm?: () => void, cancel?: () => void): void {promptAction.showDialog({title: title ?? "提示",message: content,buttons: [{text: cancelBtn ?? "取消",color: "#000000"},{text: confirmBtn ?? "确认",color: "#4169E1"}]}).then(data => {if (data.index == 1) {if (confirm) {confirm()}} else {if (cancel) {cancel()}}})
}
直接使用鸿蒙showCustomMsg弹框在一些场景是可以的,但是局限性比较大,在一些别的场景需要自定义样式,或者就只是简单想让标题和内容居中都是没有提供样式来调整,因此我们可以使用以下弹框来自定义。
一、在原生页面使用自定义弹窗
import Logger from '../common/utils/Logger'
@CustomDialog
export struct HMCustomDialog {controller: CustomDialogControllertitle: string | Resource = ''message: string | Resource = ''leftText: string | Resource = ''rightText: string | Resource = ''showLeft: boolean = trueshowRight: boolean = truecancel: () => void = () => {}confirm: () => void = () => {}
build() {Column() {Text(this.title).fontSize(18).fontColor(Color.Black).fontWeight(800).margin({ top: 10 })
Text(this.message).fontSize(16).fontColor($r('app.color.font_333333')).margin({ top: 10, bottom: 10 })
Flex({ justifyContent: FlexAlign.SpaceAround }) {Button(this.leftText).onClick(() => {this.cancel()this.controller.close()}).backgroundColor(0xffffff).fontColor(Color.Gray).visibility(this.showLeft ? Visibility.Visible : Visibility.None)
Button(this.rightText).onClick(() => {this.confirm()Logger.debug('confirm')this.controller.close()}).backgroundColor(0xffffff).fontColor($r('app.color.font_0086f3')).visibility(this.showRight ? Visibility.Visible : Visibility.None)}.margin({ bottom: 4 })}}
}
在父页面使用
MyDialogController: CustomDialogController = new CustomDialogController({builder: HMCustomDialog({title: '提示',message: '您还没有登录',leftText: '取消',rightText: '去登录',showLeft: true,showRight: true,cancel: () => {},confirm: () => {//去登录WindowUtils.getRouter().pushUrl({ url: 'pages/login/LoginPage' })},}),alignment: DialogAlignment.Center
})
build() {Column(){Button().onClick(()=>{this.MyDialogController.open()
})}}
二、在非原生页面(如方法中)需要弹出自定义弹窗时
import { ComponentContent } from '@kit.ArkUI'
import { BusinessError } from '@kit.BasicServicesKit';
import { WindowUtils } from '../common/constants/WindowUtils';
import Logger from '../common/utils/Logger';
let contentNode: ComponentContent<Content> | undefined
export interface Contents {title: stringmessage: stringconfirm?: () => void,leftText?: stringrightText?: string
}
export async function H5ShowCustomDialog(content: Contents) {
let uiContext = WindowUtils.mainWindow.getUIContext();let promptAction = uiContext.getPromptAction();contentNode = new ComponentContent(uiContext, wrapBuilder(customDialogComponent), content);
try {promptAction.openCustomDialog(contentNode)
} catch (error) {let message = (error as BusinessError).message;let code = (error as BusinessError).code;Logger.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);}
}
export function H5CloseCustomDialog() {let uiContext = WindowUtils.mainWindow.getUIContext();let promptAction = uiContext.getPromptAction();
try {promptAction.closeCustomDialog(contentNode)} catch (error) {let message = (error as BusinessError).message;let code = (error as BusinessError).code;Logger.error(`CloseCustomDialog args error code is ${code}, message is ${message}`);} finally {contentNode = undefined}
}
@Builder
function
customDialogComponent(content: Contents) {Column() {Dialog({content: content,})}.width('65%').height(150).borderRadius(15).justifyContent(FlexAlign.Center).backgroundColor(Color.White)
}
@Component
export struct Dialog {content: Contents = {} as Contents
build() {Column() {Text(this.content.title).fontSize(18).fontColor(Color.Black).fontWeight(700).margin({ top: 10 })
Text(this.content.message).fontSize(16).fontColor($r('app.color.font_333333')).margin({ top: 10, bottom: 10 })
//适用于非原生页面的两种提示框,传confirm提供确认和取消键,否则只提供确认键if (this.content.confirm) {Flex({ justifyContent: FlexAlign.SpaceAround }) {Button(this.content.leftText ? this.content.leftText : '取消').onClick(() => {H5CloseCustomDialog()
}).backgroundColor(0xffffff).fontColor(Color.Gray)
Button(this.content.rightText ? this.content.rightText : '确定').onClick(() => {if (this.content.confirm) {this.content.confirm()}}).backgroundColor(0xffffff).fontColor($r('app.color.font_0086f3'))}.margin({ bottom: 4 })} else {Button('确定').onClick(() => {H5CloseCustomDialog()
}).backgroundColor(0xffffff).fontColor($r('app.color.font_0086f3'))}}.justifyContent(FlexAlign.SpaceBetween).width('100%').height('100%')}
}
调用封装好的方法即可
第一种样式
let content: Contents = {title: '提示',message: e,
}
H5ShowCustomDialog(content)
第二种样式
const confirm: () => void = () => {Toolkit.cleanAppCache()H5CloseCustomDialog()
}
let cache = (bundleStats.cacheSize / 1024 / 1024)
let content: Contents = {title: '温馨提示',message: `缓存大小:${cache > 1 ? cache.toFixed(2) + 'MB' : (cache * 1024).toFixed() + 'KB'}`,rightText:'确认清理',confirm: confirm
}
H5ShowCustomDialog(content)