目录
前言
最近在学习窗口的时候想起来之前的一个问题,如何实现一个全局的倒计时弹窗,监听触摸事件,可以在任何页面展示并自动关闭。
问题
在Openharmony4.1 api11版本@ohos.promptAction模块中提供了打开和关闭自定义弹窗的方法:openCustomDialog11+以及closeCustomDialog11+
CustomDialogOptions提供了CustomBuilder参数可以结合@Builder生成用户希望的自定义组件。
但是相应在api10中只提供了showDialog方法弹窗选项,有以下问题:
1. 自定义弹窗选项很少,只可以改变内容文本、标题文本,无法自定义样式,无法加入倒计时。
2. 打开的dialog需要手动点击才可以关闭,不会随页面跳转消失。
方案
学习窗口之后,发现@window提供了createSubWindow接口创建应用子窗口,可以改变其大小、位置、窗口背景色等属性;通过setUIContent和showWindow接口加载显示子窗口的具体内容;同时可根据具体实现逻辑,使用destroyWindow接口销毁子窗口。这样完美解决了使用showdialog产生的问题。
先来看看官网介绍子窗口的使用。
import UIAbility from '@ohos.app.ability.UIAbility';
let windowStage_ = null;
let sub_windowClass = null;
export default class EntryAbility extends UIAbility {
showSubWindow() {
// 1.创建应用子窗口。
windowStage_.createSubWindow("mySubWindow", (err, data) => {
if (err.code) {
console.error('Failed to create the subwindow. Cause: ' + JSON.stringify(err));
return;
}
sub_windowClass = data;
console.info('Succeeded in creating the subwindow. Data: ' + JSON.stringify(data));
// 2.子窗口创建成功后,设置子窗口的位置、大小及相关属性等。
// 第一个参数窗口在x轴方向移动的值,单位为px
// 第二个参数窗口在y轴方向移动的值,单位为px
sub_windowClass.moveWindowTo(300, 300, (err) => {
if (err.code) {
console.error('Failed to move the window. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in moving the window.');
});
// 第一个参数目标窗口的宽度,单位为px;
// 第二个参数目标窗口的高度,单位为px;
sub_windowClass.resize(500, 500, (err) => {
if (err.code) {
console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in changing the window size.');
});
// 3.为子窗口加载对应的目标页面。
sub_windowClass.setUIContent("pages/page3", (err) => {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in loading the content.');
// 3.显示子窗口。
sub_windowClass.showWindow((err) => {
if (err.code) {
console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in showing the window.');
});
});
})
}
destroySubWindow() {
// 4.销毁子窗口。当不再需要子窗口时,可根据具体实现逻辑,使用destroy对其进行销毁。
sub_windowClass.destroyWindow((err) => {
if (err.code) {
console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in destroying the window.');
});
}
onWindowStageCreate(windowStage) {
windowStage_ = windowStage;
// 开发者可以在适当的时机,如主窗口上按钮点击事件等,创建子窗口。并不一定需要在onWindowStageCreate调用,这里仅作展示
this.showSubWindow();
}
onWindowStageDestroy() {
// 开发者可以在适当的时机,如子窗口上点击关闭按钮等,销毁子窗口。并不一定需要在onWindowStageDestroy调用,这里仅作展示
this.destroySubWindow();
}
};
于是我们仿照官方示例,加入到我们的代码中。
一、创建子窗口
在我们希望拉起子窗口的地方中加入showSubWindow方法,此时我们的windowStage_还没有初始化,所以我们要获取当前主窗口的窗口管理器,找到当前Ability(如EntryAbility.ts)的onWindowStageCreate(),我们通过AppStorage来传递windowStage,AppStorage支持应用的主线程内多个UIAbility实例间的状态共享。
onWindowStageCreate(windowStage: window.WindowStage) {
···
AppStorage.setOrCreate('windowStage_', windowStage);
···
}
二、加载子窗口目标页面
替换示例中setUIContent中的'pages/page3'为自定义页面。
三、销毁子窗口
接下来在我们希望关闭子窗口的地方加入destroySubWindow方法,这时需要sub_windowClass,即拉起子窗口时创建的子窗口对象,这个对象我们可以在showSubWindow中windowStage_.createSubWindow方法的回调函数中获取。同样我们可以通过AppStorage进行传递。
(AppStorage.get('windowStage_') as window.WindowStage).createSubWindow("mySubWindow", (err: BusinessError, data) => {
let errCode: number = err.code;
if (errCode) {
console.error('Failed to create the subwindow. Cause: ' + JSON.stringify(err));
return;
}
AppStorage.setOrCreate('sub_windowClass', data);
})