HarmonyOS 鸿蒙Next中如何创建一个不会被应用内任何页面和窗口遮盖的Dialog

HarmonyOS 鸿蒙Next中如何创建一个不会被应用内任何页面和窗口遮盖的Dialog 目前我的App内存在这样的逻辑:

启动Ability后,内部主窗口自动打开了我指向的Page,这时候我在这个Page内打开一个弹框,我希望的是这个弹框是比较重要的,需要用户响应结束后才能继续操作App。但是这时候Page内还有其他逻辑正在运行,他可能会打开一个新的Window(通过的方式创建子窗口),子窗口内也有自己的Page和UI逻辑,而这时候这个子窗口就把根窗口打开的那个Dialog覆盖掉了。

我还查看了这个API文档中提到的,其中有个showInSubWindows配置,似乎是可以把Dialog作为一个独立的Window,估计这个用法适用于dialog是最后打开的,Window就是后打开的在最上面。 但是我的逻辑是希望Dialog是单独一层,显示在所有Window之上,即使后面再开新的Window,也不会遮盖先打开的这个Dialog。

请问大佬们有没有知道解决方案的呢?

https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-promptaction#basedialogoptions11


更多关于HarmonyOS 鸿蒙Next中如何创建一个不会被应用内任何页面和窗口遮盖的Dialog的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复

【背景知识】

【解决方案】

目前规格上不支持,弹窗所在的窗口取决于自身锚点的UI上下文,它所属的窗口是在打开时确定的,它通过主窗口页面的点击操作唤起,因此锚点在主窗口上,其层级也就高于主窗口页面而低于子窗口。

更多关于HarmonyOS 鸿蒙Next中如何创建一个不会被应用内任何页面和窗口遮盖的Dialog的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


可以使用子窗口模式

import { window } from '@kit.ArkUI';

let dialogWindow: window.Window;
async function createDialogWindow() {
  const context = this as common.UIAbilityContext;
  // 创建子窗口参数
  const config: window.WindowTypeOptions = {
    name: 'dialogWindow',
    windowType: window.WindowType.TYPE_APP_DIALOG,
    ctx: context
  };
  // 创建并显示窗口
  dialogWindow = await window.createWindow(context, config);
  dialogWindow.moveTo(0, 0).then(() => {
    dialogWindow.resize(display.getDefaultDisplaySync().width, display.getDefaultDisplaySync().height);
    dialogWindow.loadContent('pages/DialogPage');
  });
}

通过createSubWindow创建独立子窗口承载弹窗,利用窗口系统自动管理Z轴顺序的特性,后续创建的子窗口默认会覆盖之前的窗口。

强制弹窗窗口置顶可以结合showInSubWindow参数与窗口生命周期管理,来确保弹窗窗口始终保持最高层级。

主要步骤----------

  1. 创建独立弹窗子窗口
let dialogWindow: window.WindowClass | null = null;

// 创建专用弹窗子窗口
context.windowStage.createSubWindow('globalDialog', (err, windowClass) => {
    if (err.code) return;
    dialogWindow = windowClass;
    windowClass.setWindowLayoutFullScreen(true); // 全屏布局避免遮挡
    windowClass.setUIContent("pages/GlobalDialogPage"); // 弹窗内容页
});
  1. 设置弹窗窗口属性
dialogWindow.on('windowStageEvent', (event) => {
    if (event.type === window.WindowStageEventType.SHOW) {
        // 禁止手势穿透
        dialogWindow.setTouchable(true);
        // 设置窗口置顶标志位
        dialogWindow.setWindowProperties({
            zOrder: window.ZOrder.ALWAYS_ON_TOP
        });
    }
});
  1. 通过API触发弹窗显示
promptAction.showDialog({
    title: '重要提示',
    message: '请先处理当前操作',
    showInSubWindow: true, // 参数[原题链接]
    buttons: [{ text: '确认' }]
}, (err, result) => {
    if (result.index === 0) {
        dialogWindow.destroy();
    }
});

研究一下第三方弹框:https://gitee.com/open9527/OpenHarmony

高度解耦

在HarmonyOS Next中,要创建置顶Dialog需使用WindowManager。通过WindowStage获取WindowManager实例,设置WindowType.TYPE_SYSTEM_ALERT窗口类型,并配置FLAG_NOT_TOUCH_MODALFLAG_NOT_FOCUSABLE标志。关键代码示例:

let windowManager = windowStage.getWindowManager()
let dialogWindow = await windowManager.createWindow("dialog", WindowType.TYPE_SYSTEM_ALERT)
dialogWindow.setWindowFlags(WindowFlag.FLAG_NOT_TOUCH_MODAL | WindowFlag.FLAG_NOT_FOCUSABLE)

需在module.json5中声明ohos.permission.SYSTEM_FLOAT_WINDOW权限。

在HarmonyOS Next中要实现始终置顶的Dialog,可以使用WindowStage的showDialogForSystem方法。这个方法创建的Dialog会显示在系统级别,不会被应用内其他窗口覆盖。具体实现步骤如下:

  1. 获取当前WindowStage实例:
let windowStage = this.context.windowStage;
  1. 使用showDialogForSystem方法创建系统级Dialog:
windowStage.showDialogForSystem({
  title: '重要提示',
  message: '请先处理此弹窗',
  buttons: [
    {
      text: '确定',
      color: '#FF0000',
      action: () => {
        // 确定按钮回调
      }
    }
  ]
});

这种方法创建的Dialog会显示在所有应用窗口之上,包括后续通过createSubWindow创建的子窗口。需要注意的是,系统级Dialog的样式和交互方式可能会有一些限制,建议参考官方文档进行样式调整。

如果需要对Dialog有更多自定义需求,也可以考虑创建一个全屏透明的Window,在这个Window中实现自定义Dialog效果,这样也能保证不会被其他窗口覆盖。

回到顶部