HarmonyOS鸿蒙Next中如何实现新的页面覆盖弹窗?
HarmonyOS鸿蒙Next中如何实现新的页面覆盖弹窗? 在自定义弹窗进行操作跳转到新页面后,怎么让新页面显示在弹窗上面,并且退出这个页面的时候弹窗还在
【背景知识】
常见弹窗实现方式可以分为以下几种:
-
自定义弹窗(CustomDialog)是一种基础自定义弹窗,通过CustomDialogController控制。使用弹窗组件时,可自定义弹窗的样式与内容。
-
@ohos.promptAction(弹窗)是一种不依赖UI组件的全局自定义弹出框。从API10开始,可以通过使用UIContext中的getPromptAction方法获取当前UI上下文关联的PromptAction对象。并且可以通过配置isModal来实现模态和非模态弹窗。isModal为true时,弹出框为模态弹窗。isModal为false时,弹出框为非模态弹窗。
-
@ohos.window(窗口)提供管理窗口的一些基础能力,包括对当前窗口的创建、销毁、各属性设置,以及对各窗口间的管理调度。通过Configuration接口设置窗口属性。可通过windowType参数设置窗口类型为模态窗口以及子窗口等。
-
通过组件的通用zIndex/visibility属性以及if/else语法控制组件的显隐,模拟实现自定义弹窗效果。
-
通过OverlayManager设置浮层的方式实现弹窗。
-
通过NavDestinationMode.DIALOG弹窗类型设置弹窗。此时整个NavDestination无组件占位部分默认透明显示。
-
创建模态窗口通过bindSheet等模态窗口属性实现弹窗效果。
路由跳转方式:
-
Navigation导航是官方推荐路由方式。Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(NavDestination的子组件),首页和非首页通过路由进行切换。
-
@ohos.router(页面路由)也是官方的一种路由方式,目前已不再演进。
【问题定位】
-
出现该问题的根本原因是页面弹窗不是页面的一个组件或者与页面不是一个显示层级,弹窗显示层级在所有的页面之上。其中自定义弹窗(CustomDialog)、默认模式下的@ohos.promptAction(弹窗)、OverlayManager浮层、模态窗口等都是显示在Page页面层级之上。导致在不关闭弹窗的情况下,新打开的页面都在弹窗下面。
-
而不同路由跳转方式的底层实现不同,导致问题也存在一定的差异性。
- Navigation导航
通过Navigation导航跳转时,由于Navigation页面为根页面,与NavDestination页面为父子组件关系,所有的NavDestination子页面在通过自定义弹窗(CustomDialog)、@ohos.window(窗口)、OverlayManager浮层、模态窗口等方式创建窗口弹窗时,弹窗会显示在根页面上,在弹窗内进行子页面跳转时,弹窗会覆盖在所有的子页面上。例如,将Navigation页面的mode()属性参数NavigationMode.Stack改为NavigationMode.Auto,并采用平板展示时,能更直观的复现上述问题。
- @ohos.router(页面路由)
而若以@ohos.window(窗口)创建窗口方式创建弹窗,由于每次创建的是一个新的@Entry子窗口页面,所以可以实现和Navigation导航中NavDestinationMode.DIALOG弹窗类似的效果。
【分析结论】
根本原因是实现弹窗的显示层级在Page页面上,由于不同导航方式实现逻辑不一致,所以不同的导航方式,可以通过不同的窗口实现方式,实现“页面级弹窗”。
【解决方案】
不同路由跳转方式存在不同的实现方案,方案如下:
方案一:适用于Navigation导航与@ohos.router(页面路由)两种导航方式。
通过组件的通用zIndex/visibility属性以及if/else语法控制组件的显隐,模拟实现自定义弹窗效果:
-
自定义可复用的自定义组件,作为弹窗组件;
-
通过状态管理,控制自定义组件的zIndex属性的显示层级、visibility属性以及if/else语法的显隐达到自定义弹窗的目的。
注意事项:
通过zIndex、visibility以及if/else显隐控制时,需要采用Stack()组件进行组件重叠处理。
方案二:适用于Navigation导航和方式。
当采用@ohos.router(页面路由)方式跳转NavDestinationMode.DIALOG页面时不适用,会导致弹窗蒙层不透明。
-
自定义一个NavDestination组件设置mode为NavDestinationMode.DIALOG弹窗类型,此时整个NavDestination无组件占位部分默认透明显示。
-
定义页面路由,采用push方法将弹窗页面推入路由栈内,由于透明可以看到下一级页面,实现打开弹窗效果。采用pop方法删除路由栈内弹窗页面,实现关闭弹窗效果。
NavDestinationMode.DIALOG实现自定义弹窗方案,示例代码如下:
-
创建Navigation根页面。
-
创建Index2子页面,并定义到弹窗页面的路由。
-
创建并自定义CustomDialog子页面,并定义到Index3页面的路由。
-
创建Index3子页面。
方案三:适用于Navigation导航与@ohos.router(页面路由)两种导航方式。
在API15的版本中新提供了页面级弹出框。当弹出框的options入参中设置levelMode属性,值为LevelMode.EMBEDDED时表示开启页面级弹出框能力。
-
@ohos.router(页面路由)跳转应用示例详情参考官方文档。
-
Navigation用法参考示例:参考方案一的布局形式,只修改Index2页面,核心代码参考如下:
方案四:适用于@ohos.router(页面路由)导航方式。
通过@ohos.window(窗口)创建子窗口的形式创建弹窗:
-
修改EntryAbility页面配置。
-
主页创建并调用子窗口。
-
自定义子窗口布局。
-
创建跳转测试页面。
【常见FAQ】
Q:怎样实现多层弹窗效果?
A:弹窗嵌套即可。可以使用官方弹窗组件CustomDialog嵌套CustomDialog;也可以在CustomDialog官方弹窗内采用本文方案混合使用,遵循谁后打开,谁显示在上层的原则。
Q:设置zIndex属性层级最高的情况下,为什么没效果?
A:zIndex是设置同层组件之前的渲染优先级权值,但不支持跨层比较权值。
Q:bindSheet模态弹窗用router跳转后会自动关闭,有什么办法可以让弹窗返回时自动打开弹窗?
A:可以在onpageshow内设置打开,若非强制性要求,弹窗被遮盖时都必须为打开状态时,可以考虑当弹窗显示在所有的页面上时,采用跳转时先关闭,跳转回页面后,在显示时再打开弹窗的逻辑。
更多关于HarmonyOS鸿蒙Next中如何实现新的页面覆盖弹窗?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,实现新的页面覆盖弹窗可以使用@CustomDialog
装饰器创建自定义弹窗组件。通过CustomDialogController
控制弹窗的显示与隐藏。在页面中引入弹窗组件并实例化CustomDialogController
,调用open()
方法显示弹窗,close()
方法关闭弹窗。弹窗内容可自定义布局和交互逻辑。
在HarmonyOS Next中实现页面覆盖弹窗效果,可以通过以下方式:
- 使用PageAbility + Window组合:
- 弹窗使用
WindowManager.createWindow()
创建悬浮窗 - 新页面使用
startAbility()
启动PageAbility - 设置新页面的窗口层级高于弹窗
- 关键代码示例:
// 创建弹窗窗口
let windowClass = new Window(this.context)
windowClass.setWindowType(WindowType.TYPE_APP_FLOAT)
windowClass.setWindowLevel(1) // 设置窗口层级
// 启动新页面
let want = {
bundleName: "com.example.app",
abilityName: "NewPageAbility"
}
this.context.startAbility(want, (err) => {
// 回调处理
})
- 注意事项:
- 确保新页面的WindowLevel高于弹窗
- 在页面返回时不要关闭弹窗Window
- 可以使用Window的hide()/show()控制弹窗显隐
这种方式利用了HarmonyOS的多窗口管理能力,通过控制窗口层级实现覆盖效果。