HarmonyOS鸿蒙Next中如何解除openCustomDialog依赖this.getUIContext的问题?
HarmonyOS鸿蒙Next中如何解除openCustomDialog依赖this.getUIContext的问题?
事情是这样的,我想封装一个自定义弹窗工具类,但是发现不管怎么封装,都必须传入当前的页面的UIContext。而且每个页面的UIContext都不一样,我也尝试了通过以下方式获取UIContext:
let uiContext: UIContext | undefined = AppStorageV2.connect(UIContext, 'uiContext', () => new UIContext())
但是,这种方法获取的UIContext,虽然能打开showAlertDialog,但并不能正常打开我封装的自定义弹窗。
UIContext.showAlertDialog({ message: "不允许" })
更多关于HarmonyOS鸿蒙Next中如何解除openCustomDialog依赖this.getUIContext的问题?的实战教程也可以访问 https://www.itying.com/category-93-b0.html
【背景知识】
- 通过CustomDialogController类显示自定义弹窗。使用弹窗组件时,优先考虑自定义弹窗,便于弹窗样式与内容的自定义,详情请参考自定义弹窗 (CustomDialog)。
- [@ohos.promptAction(弹窗)](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-promptaction)是一种不依赖UI组件的全局自定义弹出框。从API10开始,可以通过使用UIContext中的getPromptAction方法获取当前UI上下文关联的PromptAction对象。
【解决方案】
openCustomDialog和UIContext解除联系,可以通过封装自定义弹窗模块,仅需传入以下两个参数,调用方法即可获得自定义弹窗:
- 传入弹窗名称;
- 传入弹窗自定义内容,如文本内容,图片内容。
代码示例如下,调用的是testPromptDialog方法:
export function testPromptDialog(pageName: string, text: string) {
const that = GlobalContext.getContext().getObject(pageName) as UIContext;
if (that) {
promptAction.openCustomDialog({
builder: customDialogBuilder.bind(that, text)
}).then((dialogId: number) => {
customDialogId = dialogId;
})
}
}
开发步骤如下:
- 新建GlobalContext.ets工具类,用于页面Context的保存和获取。
export class GlobalContext {
private constructor() {}
private static instance: GlobalContext;
private _objects = new Map<string, Object>();
public static getContext(): GlobalContext {
if (!GlobalContext.instance) {
GlobalContext.instance = new GlobalContext();
}
return GlobalContext.instance;
}
getObject(value: string): Object | undefined {
return this._objects.get(value);
}
setObject(key: string, objectClass: Object): void {
this._objects.set(key, objectClass);
}
}
- 新建DialogUtils.ets工具类,工具类中已封装了自定义弹窗,以及弹出自定义弹窗的方法。拉起弹窗通过
promptAction.openCustomDialog
来实现。
import { promptAction } from '@kit.ArkUI'
import { GlobalContext } from './GlobalContext'
let customDialogId: number = 0
@Builder
export function failDialogBuilder(content: String) {
Column() {
Text(content as string)
.fontSize(20).height("30%")
Text('失败原因:' + content).fontSize(16).height("30%")
Row() {
Button("确认").onClick(() => {
promptAction.closeCustomDialog(customDialogId)
})
Blank().width(50)
Button("取消").onClick(() => {
promptAction.closeCustomDialog(customDialogId)
})
}
.margin({ top: 30 })
}.height(200).padding(5)
}
@Builder
export function successDialogBuilder(content: String) {
Column() {
Text(content as string)
.fontSize(20).height("30%")
Text('成功原因:' + content).fontSize(16).height("30%")
Row() {
Button("确认").onClick(() => {
promptAction.closeCustomDialog(customDialogId)
})
Blank().width(50)
Button("取消").onClick(() => {
promptAction.closeCustomDialog(customDialogId)
})
}
.margin({ top: 30 })
}.height(200).padding(5)
}
// 传入页面名称和文本内容
export function testPromptDialog(pageName: string, text: string, controller: Function) {
const that = GlobalContext.getContext().getObject(pageName) as UIContext;
if (that) {
promptAction.openCustomDialog({
builder: controller.bind(that, text)
}).then((dialogId: number) => {
customDialogId = dialogId;
})
}
}
- 页面初始化时存入Context,然后在入口处调用自定义弹窗封装方法。
import { GlobalContext } from '../utils/GlobalContext'
import { failDialogBuilder, successDialogBuilder, testPromptDialog } from '../utils/DialogUtils'
@Entry
@Component
struct Index {
aboutToAppear(): void {
// 设置page的Context
GlobalContext.getContext().setObject('pageName', this)
}
build() {
Row() {
Column() {
Button("promptAction失败弹窗")
.onClick(() => {
testPromptDialog("pageName", "this is dialog1", failDialogBuilder)
})
Button("promptAction成功弹窗")
.onClick(() => {
testPromptDialog("pageName", "this is dialog2", successDialogBuilder)
})
}
.width('100%')
}
.height('100%')
}
}
更多关于HarmonyOS鸿蒙Next中如何解除openCustomDialog依赖this.getUIContext的问题?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
好家伙,感觉像是隔靴搔痒。。。
弹框无法和UiContext解耦,只能和页面解耦,详情可以看这边文章 链接
有一点不明白的是,为什么 AlertDialog.show
就不需要传入 UIContext
,在方法中就可以正常调用,也不依赖于页面,代码如下:
AlertDialog.show({message: "弹窗"})
在HarmonyOS Next中,可通过@CustomDialog
装饰器创建自定义弹窗,无需依赖this.getUIContext()
。示例代码:
@CustomDialog
struct MyDialog {
build() {
// 弹窗内容
}
}
// 调用时直接使用:
MyDialog.show()
若需上下文,可通过@LocalStorageProp
或@LocalStorageLink
传递数据。对于UI控制器操作,改用@Provide
/@Consume
实现跨组件通信。
在HarmonyOS Next中,openCustomDialog
确实需要依赖正确的UIContext
才能正常工作。这是因为每个页面的UIContext
都维护着自己的组件树和渲染上下文。你遇到的问题是因为通过AppStorage
获取的UIContext
并不是当前页面的实际上下文。
建议改用以下两种方案之一:
- 使用
@BuilderParam
传递UIContext
:
@Builder
function customDialogBuilder() {
// 你的弹窗内容
}
function showDialog(uiContext: UIContext) {
uiContext.openCustomDialog({ builder: customDialogBuilder });
}
- 使用全局UI管理器(推荐):
class DialogManager {
private static currentContext?: UIContext;
static registerContext(context: UIContext) {
this.currentContext = context;
}
static showCustomDialog(builder: CustomBuilder) {
this.currentContext?.openCustomDialog({ builder });
}
}
// 在页面aboutToAppear中注册
aboutToAppear() {
DialogManager.registerContext(this.getUIContext());
}
这两种方式都能解决上下文依赖问题,第二种方案更适合大型应用。