在应用开发中,弹框Dialog和提示气泡Toast使用频繁,移动开发同学较为熟悉。但在鸿蒙响应式布局里,早期的弹框Dialog和提示气泡Toast因与UI紧密绑定,在纯逻辑类文件中无法使用。
后来API迭代对其升级,如今可在纯逻辑类中使用,实现与UI解耦。
从page界面UI上弹出 => 挂靠子窗口实现弹出 => UI框架层预留挂靠节点
由此可见,与UI强绑定的实现方式API已不推荐。
目前鸿蒙HarmonyOS对于弹框、提示气泡及相关延申组件(浮层,Popup,Menu, bindSheet, bindContentCover),都是挂靠到UI框架预留节点进行添加渲染。
弹框有两种方式:
系统定制弹框依业务复杂度有两种封装方式:
基础弹框(警告弹框,列表弹窗)
@Entry
@Component
struct AlertDialogTextPage {
build() {
Column() {
Button('showAlertDialog')
.margin(30)
.onClick(() => {
this.getUIContext().showAlertDialog(
{
title: 'title',
message: 'text',
autoCancel: true,
alignment: DialogAlignment.Center,
buttons: [{
value: 'cancel',
action: () => {
console.info('cancel')
}
},
{
enabled: true,
defaultFocus: true,
style: DialogButtonStyle.HIGHLIGHT,
value: 'ok',
action: () => {
console.info('ok')
}
}],
}
)
})
}
.width('100%')
.margin({ top: 5 })
}
}
带业务性质的PickerDialog弹框
// 日历选择器弹窗示例 (CalendarPickerDialog)
@Entry
@Component
struct PickerDialogTextPage {
private selectedDate: Date = new Date('2024-04-23')
build() {
Column() {
Button("Show CalendarPicker Dialog")
.margin(20)
.onClick(() => {
console.info("CalendarDialog.show")
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)=>{
// 当弹出框再次弹出时显示选中的是上一次确定的日期
this.selectedDate = date
}
})
})
}.width('100%')
}
}
创建节点对象并添加自定义弹框布局:
@State message: string = "测试文本"
/**
* 自定义弹框布局
* @param params
*/
@Builder
function buildText(params: Params) {
Column() {
Text(params.text)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 36 })
Button('Close')
.onClick(() => {
PromptActionClass.closeDialog()
})
}.backgroundColor('#FFF0F0F0')
}
private contentNode: ComponentContent<Object> =
new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message));
获取PromptAction对象,调用openCustomDialog弹出自定义弹框:
this.getContext().getPromptAction().openCustomDialog(PromptActionClass.contentNode)
.then(() => {
console.info('OpenCustomDialog complete.')
})
.catch((error: BusinessError) => {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);
})
修改自定义弹框对齐方式、偏移量等,添加promptAction.BaseDialogOptions:
this.getContext().getPromptAction().openCustomDialog(PromptActionClass.contentNode,{ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } })
.then(() => {
console.info('OpenCustomDialog complete.')
})
气泡有对齐方式和悬浮态设置,但不能设置字体大小和颜色。自定义字体大小和颜色需用自定义弹框或Popup。
import { promptAction } from '@kit.ArkUI'
import { BusinessError } from '@kit.BasicServicesKit'
/**
* 气泡示例
*/
@Entry
@Component
struct ToastTextPage {
build() {
Column() {
Button('Show toast').fontSize(20)
.onClick(() => {
try {
this.getUIContext().getPromptAction().showToast({
message: '测试气泡',
duration: 2000,
showMode: promptAction.ToastShowMode.TOP_MOST
});
} catch (error) {
let message = (error as BusinessError).message
let code = (error as BusinessError).code
console.error(`showToast args error code is ${code}, message is ${message}`);
};
})
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
import { BusinessError } from '@kit.BasicServicesKit';
import { ComponentContent, promptAction } from '@kit.ArkUI';
import { PromptAction, UIContext } from '@ohos.arkui.UIContext';
/**
* 自定义弹框封装
*/
export class PromptActionClass {
static ctx: UIContext;
static contentNode: ComponentContent<Object>;
static options: promptAction.BaseDialogOptions;
static setContext(context: UIContext) {
PromptActionClass.ctx = context;
}
static setContentNode(node: ComponentContent<Object>) {
PromptActionClass.contentNode = node;
}
static setOptions(options: promptAction.BaseDialogOptions) {
PromptActionClass.options = options;
}
static openDialog() {
if (PromptActionClass.contentNode!== null) {
PromptActionClass.ctx.getPromptAction().openCustomDialog(PromptActionClass.contentNode, PromptActionClass.options)
.then(() => {
console.info('OpenCustomDialog complete.')
})
.catch((error: BusinessError) => {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);
})
}
}
static closeDialog() {
if (PromptActionClass.contentNode!== null) {
PromptActionClass.ctx.getPromptAction().closeCustomDialog(PromptActionClass.contentNode)
.then(() => {
console.info('CloseCustomDialog complete.')
})
.catch((error: BusinessError) => {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`);
})
}
}
static updateDialog(options: promptAction.BaseDialogOptions) {
if (PromptActionClass.contentNode!== null) {
PromptActionClass.ctx.getPromptAction().updateCustomDialog(PromptActionClass.contentNode, options)
.then(() => {
console.info('UpdateCustomDialog complete.')
})
.catch((error: BusinessError) => {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`);
})
}
}
}
class Params {
text: string = ""
constructor(text: string) {
this.text = text;
}
}
/**
* 自定义弹框布局
* @param params
*/
@Builder
function buildText(params: Params) {
Column() {
Text(params.text)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 36 })
Button('Close')
.onClick(() => {
PromptActionClass.closeDialog()
})
}.backgroundColor('#FFF0F0F0')
}
/**
* 首页
*/
@Entry
@Component
struct Index {
@State message: string = "hello"
private ctx: UIContext = this.getUIContext();
private contentNode: ComponentContent<Object> =
new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message));
@State handlePopup: boolean = false
aboutToAppear(): void {
PromptActionClass.setContext(this.ctx);
PromptActionClass.setContentNode(this.contentNode);
PromptActionClass.setOptions({ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } });
}
build() {
Row() {
Column() {
/**
* 显示自定义气泡 更新样式
*/
Button("open dialog and update options")
.margin({ top: 50 })
.onClick(() => {
PromptActionClass.openDialog()
setTimeout(() => {
PromptActionClass.updateDialog({
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: -50 }
})
}, 1500)
})
/**
* 显示自定义气泡 更新内容数据
*/
Button("open dialog and update content")
.margin({ top: 50 })
.onClick(() => {
PromptActionClass.openDialog()
setTimeout(() => {
this.contentNode.update(new Params('update'))
}, 1500)
})
/**
* 气泡菜单
*/
Button('PopupOptions')
.onClick(() => {
this.handlePopup =!this.handlePopup
})
.bindPopup(this.handlePopup, {
message: 'This is a popup with PopupOptions',
})
/**
* 提示气泡
*/
Button('show Toast')
.onClick(() => {
let promptAction: PromptAction = this.ctx.getPromptAction();
try {
promptAction.showToast({
message: 'Message Info',
duration: 2000
});
} catch (error) {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`showToast args error code is ${code}, message is ${message}`);
};
})
/**
* 系统弹框
*/
Button('show Toast')
.onClick(() => {
let promptAction: PromptAction = this.ctx.getPromptAction();
try {
promptAction.showToast({
message: 'Message Info',
duration: 2000
});
} catch (error) {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`showToast args error code is ${code}, message is ${message}`);
};
})
}
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
}
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有