【鸿蒙】自定义弹窗非置顶解决方案 - 子窗口显示
标题概述鸿蒙自带的自定义弹窗存在不停置顶的标题,详细业务例子
在隐私弹窗的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]