愛在花開的季節 发表于 2024-10-10 13:16:31

【鸿蒙】自定义弹窗非置顶解决方案 - 子窗口显示

标题概述

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

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

工程结构



[*]LoadContentWindow.ets // 子窗口
[*]SubWindowParams.ets // 子窗口传参封装
[*]SubWindowApi.ets // 子窗口创建初始化封装
[*]SubWindowFunction.ets // 方法调用封装
1. 子窗口的创建初始化,以及烧毁,并且订阅对应事件 - SubWindowApi.ets

const EVENT_ID = 1234565; // 持续订阅事件ID

// window实例
interface Handler {
windowStage: window.WindowStage;
}


/**
* 窗口的创建,加载,显示,销毁操作
*/
export class SubWindowApi {
private subWindow: window.Window | null = null; // 初始化window实例
private Storage: LocalStorage = new LocalStorage(); // 创建页面级UI状态存储对象
// eventId为1234565的持续订阅的事件
private callbackEvent: emitter.InnerEvent = {
    eventId: EVENT_ID
}

// 显示当前窗口
private showSubWindow() {
    if (this.subWindow) {
      this.subWindow.showWindow((err: BusinessError) => {
      if (err.code) {
          console.error('Fail to show window, Cause: ' + JSON.stringify(err));
      }
      })
    }
}

// 为当前WindowStage加载命名路由页面
private loadContent(path: string) {
    if (this.subWindow) {
      // 用loadContentByName为当前窗口加载命名路由页面,通过LocalStorage传递状态属性给加载的页面
      this.subWindow.loadContentByName(path, this.Storage, (err: BusinessError) => {
      if (err.code) {
          console.error("Failed to load the content. Cause:" + JSON.stringify(err));
          return;
      }
      });
    }
}

// 销毁当前窗口
private destroySubWindow() {
    if (this.subWindow) {
      this.subWindow.destroyWindow((err) => {
      if (err.code) {
          console.error('Fail to destroy the window. Cause:' + JSON.stringify(err));
          return;
      }
      this.subWindow = null;
      });
    }
}

// 创建子窗口
private createSubWindow(windowStage: window.WindowStage | null) {
    try {
      if (!windowStage) {
      return;
      }
      windowStage.createSubWindow('subDialogWindow', (err: BusinessError, data) => {
      if (err.code) {
          console.error("Failed to create the subwindow, Cause: " + JSON.stringify(err));
          return;
      }
      this.subWindow = (data as window.Window);
      if (this.subWindow) {
          // 设置子窗口尺寸
          this.subWindow.resize(
            UIUtil.getScreenWidthPx(),
            UIUtil.getScreenHeightPx())
          // 布局避让状态栏与导航栏
          this.subWindow.setWindowLayoutFullScreen(false)
          // 设置子窗口可触
          this.subWindow.setWindowTouchable(true);
          // 设置窗口UI
          this.loadContent(entryName);
          // 展示子窗口
          this.showSubWindow();
      }
      });
    } catch (exception) {
      console.error("Failed to create the window, Cause: " + JSON.stringify(exception));
    }
}

/**
   * 订阅eventId为1234565的事件
   */
subscribeCallback(): void {
    emitter.on(this.callbackEvent, () => {
      this.hideSubWindow();
    })
}

/**
   * 取消针对eventId为1234565的事件的订阅
   */
offCallback(): void {
    emitter.off(this.callbackEvent.eventId);
}

/**
   * 更新key为'ad'的变量值
   * @param { AdWindowParams } params - 页面显示的值
   */
updateOrCreateParams(params: SubWindowParams): void {
    this.Storage.setOrCreate("subWindowParams", params);
}

/**
   * 创建并展示弹窗
   * @param { AdWindowParams } params - 页面显示的值
   * @param { Handler } handler - WindowStage对象
   */
initSubWindow(handler: Handler, params: SubWindowParams): void {
    const windowStage = handler.windowStage;
    // 注册回调
    this.subscribeCallback();
    // 初始化参数
    this.updateOrCreateParams(params);
    // 新建子窗口
    this.createSubWindow(windowStage);
}

/**
   * 隐藏弹窗
   */
hideSubWindow(): void {
    // 注销监听事件
    this.offCallback();
    // 关闭弹窗
    this.destroySubWindow();
}
}

2. 创建子窗口所加载的页面 - LoadContentWindow.ets

export const entryName: string = 'LoadContent';

const EVENT_ID = 1234565; // 持续订阅事件ID
const DURATION = 400; // 动画时间
const IMAGE_SCALE = 0.8; // 弹窗画面缩放大小


@Entry({
routeName: entryName,
storage: LocalStorage.getShared()
})
// window单独加载的命名路由页面: LoadContent
@Component
export struct LoadContent {
@LocalStorageLink('subWindowParams') params: SubWindowParams | null = null;
private windowClass: window.Window = window.findWindow('subDialogWindow');
private event: emitter.InnerEvent = {
    eventId: EVENT_ID
}
aboutToAppear(): void {
    if (this.params != null) {
      this.params.onBtnCloseListener = () => {
      // 触发回调,关闭弹窗
      emitter.emit(this.event);
      }
    }
}

onBackPress(): boolean | void {
    //监听反回键
    emitter.emit(this.event);
    return true;
}

onPageHide(): void {
    //设置子窗口蒙层颜色
    try {
      this.windowClass.setWindowBackgroundColor('#ffffff');
    } catch (exception) {
      console.error('Failed to set the background color. Cause: ' + JSON.stringify(exception));
    }
}

onPageShow(): void {
    //设置子窗口蒙层颜色
    try {
      this.windowClass.setWindowBackgroundColor("#57050505")
    } catch (exception) {
      console.error('Failed to set the background color. Cause: ' + JSON.stringify(exception));
    }
}

build() {
    Column() {
      Stack() {
      if (this.params != null) {
          dialog_privacy(this.params)
      } else {
          Text("NULL")
      }
      }
    }
    .width(UIUtil.getScreenWidthVp())
    .height(UIUtil.getScreenHeightVp())
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .transition(TransitionEffect.OPACITY.animation({
      duration: DURATION,
      curve: Curve.Ease
    }).combine(TransitionEffect.scale({
      x: IMAGE_SCALE,
      y: IMAGE_SCALE
    })))
}
}
3. 封装方法调用 - SubWindowFunction.ets

const context = getContext(this) as common.UIAbilityContext; // 获取当前页面的上下文

/**
* 创建并展示弹窗
* @param { api.SubWindowApi | null } SubWindowApi - SubWindowApi对象
* @param { window.WindowStage | undefined } windowStage - WindowStage对象
*/
export function showApiSubWindow(SubWindowApi: api.SubWindowApi | null, windowStage: window.WindowStage | undefined, params: SubWindowParams) {
SubWindowApi?.initSubWindow({ windowStage: windowStage as window.WindowStage }, params);
}

/**
* 隐藏弹窗
* @param { api.SubWindowApi | null } SubWindowApi - SubWindowApi对象
*/
export function hideApiSubWindow(SubWindowApi: api.SubWindowApi | null) {
SubWindowApi?.hideSubWindow();
}
4. 自定义传参 - SubWindowParams.ets

export class SubWindowParams {
onBtnCloseListener?: () => void

constructor() {
}

}
参考

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【鸿蒙】自定义弹窗非置顶解决方案 - 子窗口显示