【HarmonyOS Next】鸿蒙应用实现弹框DialogHub详解
【HarmonyOS Next】鸿蒙应用实现弹框DialogHub详解
一、前言
鸿蒙中实现弹框目前官方提供openCustomDialog和CustomDialog两种模式。推荐前者,详情见下图和官网文档链接:
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V14/arkts-uicontext-custom-dialog-V14
UI强绑定的实现方式API已标注不推荐。推荐使用UI框架层预留挂靠节点的方式,即openCustomDialog。
这两者的差别详见【HarmonyOS Next】鸿蒙应用弹框和提示气泡详解(一)
除此之外开源三方库DialogHub可以更加快捷的使用弹窗:
https://gitee.com/hadss/dialoghub
DialogHub底层实现原理为,使用浮层OverlayManager➕半模态页面bindSheet来实现弹框。
可以达到我们在传统Android和IOS开发中,弹框与页面生命周期绑定的效果(页面隐藏,弹框隐藏。页面销毁,弹框销毁)
DialogHub接口属性详细信息如下:
https://gitee.com/hadss/dialoghub/blob/master/docs/Reference.md
二、DialogHub的使用
目前DialogHub还是RC版本,并非Final版本。请谨慎使用。
目前DialogHub可以实现的弹框效果如下:
使用起来很简单,通过三方库通过级联的方式,获取弹框实例对象,设置弹框的样式,布局,和弹框上的属性。甚至连弹框内容模板的设置和数据的更新也通过级联属性设置,这个思路不错。
// 导依赖包之后就可操作DialogHub对象
import {
DialogHub
} from "@hadss/dialoghub"
如图所示,红框中提供了默认的三种样式的弹框。以Toast弹框举例:
showToastTest(){
DialogHub.getToast()
.setContent(wrapBuilder(TextToastBuilder))
// 自定义内容
.setConfig(CommonConstant.CUSTOM_SAMPLE_CONFIG)
// 持续时间
.setDuration(CommonConstant.DURATION_3000)
.build()
.show();
}
// 布局的内容
TextToastBuilder() {
Stack() {
Text("测试文本")
.fontColor(Color.Black)
.fontSize(52)
}
.padding({ left: 20, right: 20 })
.height(100)
}
自定义弹框:
this.specifiedLocationDialog = this.specifiedLocationDialog ?? DialogHub.getCustomDialog()
.setOperableContent(wrapBuilder(SnackbarBuilder), (action: DialogAction) => {
let param = new SnackbarParams(() => {
action.dismiss()
}, this.pageInfos)
return param
})
// DocsDot
.setStyle({
radius: $r('app.float.custom_template_sample_radius'),
shadow: CommonConstant.CUSTOM_SAMPLE_STYLE_SHADOW
})
// DocsDot
.setConfig({
dialogBehavior: { isModal: false, passThroughGesture: true },
dialogPosition: {
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: $r('app.float.specified_location_offset') }
}
})
.build();
this.specifiedLocationDialog.show();
更新弹框内容:
let intervalID: number = -1;
let time: number = CommonConstant.TIMED_DIALOG_DURATION;
let params: TimeToastParams =
new TimeToastParams(CommonConstant.TIMED_DIALOG, time + CommonConstant.TIMED_CLOSED);
// DocsCode 5
this.intervalsDisappearsDialog = this.intervalsDisappearsDialog ?? DialogHub.getCustomDialog()
.setContent(wrapBuilder(TimeToastBuilder), params)
.setStyle({
radius: $r('app.float.popup_disappears_intervals_radius'),
shadow: CommonConstant.CUSTOM_SAMPLE_STYLE_SHADOW
})
.setAnimation({ dialogAnimation: AnimationType.UP_DOWN })
.setConfig({
dialogBehavior: { isModal: false, passThroughGesture: true },
dialogPosition: {
alignment: DialogAlignment.Top,
offset: { dy: $r('app.float.popup_disappears_intervals_offset'), dx: 0 }
}
})
.build();
this.intervalsDisappearsDialog.show();
intervalID = setInterval(() => {
time -= 1;
params.content = time + CommonConstant.TIMED_CLOSED;
this.intervalsDisappearsDialog?.updateContent(params)
if (time <= 0 && intervalID) {
this.intervalsDisappearsDialog?.dismiss();
clearInterval(intervalID);
}
}, CommonConstant.DURATION_1000);
三、源码示例
首先配置依赖:
{
"modelVersion": "5.0.0",
"description": "Please describe the basic information.",
"dependencies": {
"@hadss/dialoghub": "^1.0.0-rc.1"
},
"devDependencies": {
"@ohos/hypium": "1.0.19",
"@ohos/hamock": "1.0.0"
},
"dynamicDependencies": {}
}
之后导入包,进行调用:
import { DialogHub } from '@hadss/dialoghub';
import { getContext } from '@ohos.app.ability';
import CommonConstant from '../utils/CommonConstant';
// 假设的 TextToastParams 类型
interface TextToastParams {
title?: string;
}
// TextToastBuilder 构建器函数
export function TextToastBuilder(param: TextToastParams) {
Stack() {
Text(param?.title ?? CommonConstant.PURE_TEXT)
.fontColor($r('app.color.item_text_color'))
.fontSize($r('app.float.font_size_regular'))
}
.padding({ left: $r('app.float.text_toast_padding'), right: $r('app.float.text_toast_padding') })
.height($r('app.float.text_toast_height'))
}
// 假设的组件扩展,用于按钮样式
(Button)
function superFancyButton() {
return this
.width(CommonConstant.FULL_LENGTH)
.height($r('app.float.index_action_height'))
.margin({ bottom: $r('app.float.index_action_margin') })
.fontSize($r('app.float.font_size_medium'))
.fontWeight(FontWeight.Medium)
.backgroundColor($r('app.color.base_blue'));
}
struct DialogHubExample {
// 获取 UI 上下文
getUIContext() {
return getContext();
}
aboutToAppear(): void {
// 初始化 DialogHub
DialogHub.init(this.getUIContext());
// 开启日志
DialogHub.openLog('DEBUG');
// 创建自定义模板
DialogHub.createCustomTemplate(CommonConstant.CUSTOM_TEMPLATE_SIMPLE)
.setContent(wrapBuilder(TextToastBuilder))
.setStyle({ backgroundColor: Color.White })
.setConfig({ dialogBehavior: { passThroughGesture: true, isModal: false } })
.register();
}
showCustomDialog() {
// 显示自定义模板的弹框
DialogHub.show({
templateName: CommonConstant.CUSTOM_TEMPLATE_SIMPLE,
data: {
// 传递数据给弹框
title: '这是自定义弹框的标题'
}
});
}
build() {
Column({ space: 20 }) {
Button('显示自定义弹框', { stateEffect: true, type: ButtonType.Capsule })
.superFancyButton()
.onClick(() => {
this.showCustomDialog();
});
}
.width('100%')
.height('100%')
.padding({ top: 20, bottom: 20, left: 20, right: 20 });
}
}