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

6 回复

【背景知识】

【解决方案】

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;
    })
  }
}

开发步骤如下:

  1. 新建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);
  }
}
  1. 新建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;
    })
  }
}
  1. 页面初始化时存入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并不是当前页面的实际上下文。

建议改用以下两种方案之一:

  1. 使用@BuilderParam传递UIContext
@Builder
function customDialogBuilder() {
  // 你的弹窗内容
}

function showDialog(uiContext: UIContext) {
  uiContext.openCustomDialog({ builder: customDialogBuilder });
}
  1. 使用全局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());
}

这两种方式都能解决上下文依赖问题,第二种方案更适合大型应用。

回到顶部