ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【鸿蒙】自定义弹窗非置顶解决方案 - 子窗口显示 [打印本页]

作者: 愛在花開的季節    时间: 2024-10-10 13:16
标题: 【鸿蒙】自定义弹窗非置顶解决方案 - 子窗口显示
标题概述

鸿蒙自带的自定义弹窗存在不停置顶的标题,详细业务例子
在隐私弹窗的Dialog里通过router跳转到隐私协议内容页后,弹窗不停处于最外层。按照真实业务,应该是在隐私弹窗的上层压入隐私协议,退出隐私协议页面后,弹窗还在。
目前鸿蒙自带的@CustomDialog 以及ComponentContent 封装弹窗类组件两种API实现结果均是弹窗不停置顶
解决方案

目前有两种解决方案
1.子窗口: 通过创建子窗口,并在子窗口Page内加载@Builder自定义组件( 弹窗 ) —— 本文
2.关闭 - 打开:通过订阅openCustomDialog和closeCustomDialog事件来控制显隐,实现业务。
详细实现

工程结构


1. 子窗口的创建初始化,以及烧毁,并且订阅对应事件 - SubWindowApi.ets

  1. const EVENT_ID = 1234565; // 持续订阅事件ID
  2. // window实例
  3. interface Handler {
  4.   windowStage: window.WindowStage;
  5. }
  6. /**
  7. * 窗口的创建,加载,显示,销毁操作
  8. */
  9. export class SubWindowApi {
  10.   private subWindow: window.Window | null = null; // 初始化window实例
  11.   private Storage: LocalStorage = new LocalStorage(); // 创建页面级UI状态存储对象
  12.   // eventId为1234565的持续订阅的事件
  13.   private callbackEvent: emitter.InnerEvent = {
  14.     eventId: EVENT_ID
  15.   }
  16.   // 显示当前窗口
  17.   private showSubWindow() {
  18.     if (this.subWindow) {
  19.       this.subWindow.showWindow((err: BusinessError) => {
  20.         if (err.code) {
  21.           console.error('Fail to show window, Cause: ' + JSON.stringify(err));
  22.         }
  23.       })
  24.     }
  25.   }
  26.   // 为当前WindowStage加载命名路由页面
  27.   private loadContent(path: string) {
  28.     if (this.subWindow) {
  29.       // 用loadContentByName为当前窗口加载命名路由页面,通过LocalStorage传递状态属性给加载的页面
  30.       this.subWindow.loadContentByName(path, this.Storage, (err: BusinessError) => {
  31.         if (err.code) {
  32.           console.error("Failed to load the content. Cause:" + JSON.stringify(err));
  33.           return;
  34.         }
  35.       });
  36.     }
  37.   }
  38.   // 销毁当前窗口
  39.   private destroySubWindow() {
  40.     if (this.subWindow) {
  41.       this.subWindow.destroyWindow((err) => {
  42.         if (err.code) {
  43.           console.error('Fail to destroy the window. Cause:' + JSON.stringify(err));
  44.           return;
  45.         }
  46.         this.subWindow = null;
  47.       });
  48.     }
  49.   }
  50.   // 创建子窗口
  51.   private createSubWindow(windowStage: window.WindowStage | null) {
  52.     try {
  53.       if (!windowStage) {
  54.         return;
  55.       }
  56.       windowStage.createSubWindow('subDialogWindow', (err: BusinessError, data) => {
  57.         if (err.code) {
  58.           console.error("Failed to create the subwindow, Cause: " + JSON.stringify(err));
  59.           return;
  60.         }
  61.         this.subWindow = (data as window.Window);
  62.         if (this.subWindow) {
  63.           // 设置子窗口尺寸
  64.           this.subWindow.resize(
  65.             UIUtil.getScreenWidthPx(),
  66.             UIUtil.getScreenHeightPx())
  67.           // 布局避让状态栏与导航栏
  68.           this.subWindow.setWindowLayoutFullScreen(false)
  69.           // 设置子窗口可触
  70.           this.subWindow.setWindowTouchable(true);
  71.           // 设置窗口UI
  72.           this.loadContent(entryName);
  73.           // 展示子窗口
  74.           this.showSubWindow();
  75.         }
  76.       });
  77.     } catch (exception) {
  78.       console.error("Failed to create the window, Cause: " + JSON.stringify(exception));
  79.     }
  80.   }
  81.   /**
  82.    * 订阅eventId为1234565的事件
  83.    */
  84.   subscribeCallback(): void {
  85.     emitter.on(this.callbackEvent, () => {
  86.       this.hideSubWindow();
  87.     })
  88.   }
  89.   /**
  90.    * 取消针对eventId为1234565的事件的订阅
  91.    */
  92.   offCallback(): void {
  93.     emitter.off(this.callbackEvent.eventId);
  94.   }
  95.   /**
  96.    * 更新key为'ad'的变量值
  97.    * @param { AdWindowParams } params - 页面显示的值
  98.    */
  99.   updateOrCreateParams(params: SubWindowParams): void {
  100.     this.Storage.setOrCreate("subWindowParams", params);
  101.   }
  102.   /**
  103.    * 创建并展示弹窗
  104.    * @param { AdWindowParams } params - 页面显示的值
  105.    * @param { Handler } handler - WindowStage对象
  106.    */
  107.   initSubWindow(handler: Handler, params: SubWindowParams): void {
  108.     const windowStage = handler.windowStage;
  109.     // 注册回调
  110.     this.subscribeCallback();
  111.     // 初始化参数
  112.     this.updateOrCreateParams(params);
  113.     // 新建子窗口
  114.     this.createSubWindow(windowStage);
  115.   }
  116.   /**
  117.    * 隐藏弹窗
  118.    */
  119.   hideSubWindow(): void {
  120.     // 注销监听事件
  121.     this.offCallback();
  122.     // 关闭弹窗
  123.     this.destroySubWindow();
  124.   }
  125. }
复制代码
2. 创建子窗口所加载的页面 - LoadContentWindow.ets

  1. export const entryName: string = 'LoadContent';
  2. const EVENT_ID = 1234565; // 持续订阅事件ID
  3. const DURATION = 400; // 动画时间
  4. const IMAGE_SCALE = 0.8; // 弹窗画面缩放大小
  5. @Entry({
  6.   routeName: entryName,
  7.   storage: LocalStorage.getShared()
  8. })
  9.   // window单独加载的命名路由页面: LoadContent
  10. @Component
  11. export struct LoadContent {
  12.   @LocalStorageLink('subWindowParams') params: SubWindowParams | null = null;
  13.   private windowClass: window.Window = window.findWindow('subDialogWindow');
  14.   private event: emitter.InnerEvent = {
  15.     eventId: EVENT_ID
  16.   }
  17.   aboutToAppear(): void {
  18.     if (this.params != null) {
  19.       this.params.onBtnCloseListener = () => {
  20.         // 触发回调,关闭弹窗
  21.         emitter.emit(this.event);
  22.       }
  23.     }
  24.   }
  25.   onBackPress(): boolean | void {
  26.     //监听反回键
  27.     emitter.emit(this.event);
  28.     return true;
  29.   }
  30.   onPageHide(): void {
  31.     //设置子窗口蒙层颜色
  32.     try {
  33.       this.windowClass.setWindowBackgroundColor('#ffffff');
  34.     } catch (exception) {
  35.       console.error('Failed to set the background color. Cause: ' + JSON.stringify(exception));
  36.     }
  37.   }
  38.   onPageShow(): void {
  39.     //设置子窗口蒙层颜色
  40.     try {
  41.       this.windowClass.setWindowBackgroundColor("#57050505")
  42.     } catch (exception) {
  43.       console.error('Failed to set the background color. Cause: ' + JSON.stringify(exception));
  44.     }
  45.   }
  46.   build() {
  47.     Column() {
  48.       Stack() {
  49.         if (this.params != null) {
  50.           dialog_privacy(this.params)
  51.         } else {
  52.           Text("NULL")
  53.         }
  54.       }
  55.     }
  56.     .width(UIUtil.getScreenWidthVp())
  57.     .height(UIUtil.getScreenHeightVp())
  58.     .alignItems(HorizontalAlign.Center)
  59.     .justifyContent(FlexAlign.Center)
  60.     .transition(TransitionEffect.OPACITY.animation({
  61.       duration: DURATION,
  62.       curve: Curve.Ease
  63.     }).combine(TransitionEffect.scale({
  64.       x: IMAGE_SCALE,
  65.       y: IMAGE_SCALE
  66.     })))
  67.   }
  68. }
复制代码
3. 封装方法调用 - SubWindowFunction.ets

  1. const context = getContext(this) as common.UIAbilityContext; // 获取当前页面的上下文
  2. /**
  3. * 创建并展示弹窗
  4. * @param { api.SubWindowApi | null } SubWindowApi - SubWindowApi对象
  5. * @param { window.WindowStage | undefined } windowStage - WindowStage对象
  6. */
  7. export function showApiSubWindow(SubWindowApi: api.SubWindowApi | null, windowStage: window.WindowStage | undefined, params: SubWindowParams) {
  8.   SubWindowApi?.initSubWindow({ windowStage: windowStage as window.WindowStage }, params);
  9. }
  10. /**
  11. * 隐藏弹窗
  12. * @param { api.SubWindowApi | null } SubWindowApi - SubWindowApi对象
  13. */
  14. export function hideApiSubWindow(SubWindowApi: api.SubWindowApi | null) {
  15.   SubWindowApi?.hideSubWindow();
  16. }
复制代码
4. 自定义传参 - SubWindowParams.ets

  1. export class SubWindowParams {
  2.   onBtnCloseListener?: () => void
  3.   
  4.   constructor() {
  5.   }
  6. }
复制代码
参考

https://gitee.com/harmonyos-cases/cases/blob/master/CommonAppDevelopment/feature/customdialog/README.md

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4