前言:我们项目中有用到全局的悬浮框,看了很多博客和文档,鸿蒙的全局悬浮框也是在新建的window上加载一个悬浮框的,我这一节主要是来讲如何新建一个window的方法,下一节讲在window上新建一个悬浮框的方法。
系统window api可自行参考,不理解的方法,也可以参考系统Api。
1.获取window需要的windowStage方法
创建window的方法,windowStage.createSubWindow(‘mySubWindow’, (err: BusinessError, data) ,windowStage如何来呢?
我们是在首页才需要创建,因此在入口类EntryAbility的地方,需要存储windowStage
AppStorage.setOrCreate("windowStage", windowStage);
获取windowStage的方法,在你需要创建window的页面,获取一下就ok了
@State windowStage: window.WindowStage = AppStorage.get('windowStage') as window.WindowStage;
2.创建新的window
export class FlowWindowOptions{
//windowStage
windowStage: window.WindowStage;
//新建window名字
windowName: string;
//window加载内容页面路径
windowShowInContentName: string;
//window背景颜色
windowBackGroundColor?: string;
//新建window大小
windowInitSize?: Size;
//新建window坐标
windowInitPostion?:Position;
//系统的导航栏高度,用来控制window的边界
windowNavHeight?:number;
//系统的底部tabbar栏高度,用来控制window的边界
windowTabbarHeight?:number;
constructor(windowStage: window.WindowStage, windowName: string, windowShowInContentName: string,
windowBackGroundColor?: string,windowInitPostion?:Position,windowInitSize?:Size,windowNavHeight?:number,windowTabbarHeight?:number) {
this.windowStage = windowStage;
this.windowName = windowName;
this.windowShowInContentName = windowShowInContentName;
this.windowBackGroundColor = windowBackGroundColor;
this.windowInitPostion = windowInitPostion;
this.windowInitSize = windowInitSize;
this.windowNavHeight = windowNavHeight;
this.windowTabbarHeight = windowTabbarHeight;
}
这是我自定义的新建window的option类,主要是给window传参数的,
创建window,需要一个新的window名字,参数中需要一个window的名字,用来区分不同的window
this.windowOptions.windowStage.createSubWindow(this.windowOptions.windowName, (err, win) => {
})
设置window的初始位置,window窗口可以在屏幕的任何位置,但是我处理了一些边界问题,只能放在导航栏之下,以及底部导航栏以上位置,初始化的时候,如果position设置的不合理,会恢复默认位置,因为我们的项目悬浮框初始放在右侧,所以我会用屏幕的宽度-window的宽度
win.moveWindowTo(display.getDefaultDisplaySync().width - vp2px(positionX), vp2px(positionY), (err) => {
设置window的大小,窗口初始化一个大小,后续可以更改窗口的大小
win.resize(window_w, window_h, (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.');
});
设置window加载的内容,窗口构建之后就需要加载窗口的内容,setUIContent就是加载窗口内容的方法,这个是个路径
win.setUIContent(this.windowOptions.windowShowInContentName, (err: BusinessError) => {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
win.setWindowBackgroundColor(this.windowOptions.windowBackGroundColor?this.windowOptions.windowBackGroundColor:'#12ffff00')
console.info('Succeeded in loading the content.');
// 显示悬浮窗。
win.showWindow((err: BusinessError) => {
if (err.code) {
console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in showing the window.');
});
});
销毁window
这是销毁window的方法,比如某个界面不需要显示悬浮框就可以销毁,或者隐藏它
// 自定义销毁悬浮窗方法
destroyFloatWindow(windowName:string) {
// 用windowClass调用destroyWindow销毁悬浮窗
window.findWindow(windowName).destroyWindow((err) => {
if (err.code) {
console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in destroying the window.');
});
}
完整的代码:
import { display, window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
export class FlowWindowOptions{
windowStage: window.WindowStage;
windowName: string;
windowShowInContentName: string;
windowBackGroundColor?: string;
windowInitSize?: Size;
windowInitPostion?:Position;
windowNavHeight?:number;
windowTabbarHeight?:number;
constructor(windowStage: window.WindowStage, windowName: string, windowShowInContentName: string,
windowBackGroundColor?: string,windowInitPostion?:Position,windowInitSize?:Size,windowNavHeight?:number,windowTabbarHeight?:number) {
this.windowStage = windowStage;
this.windowName = windowName;
this.windowShowInContentName = windowShowInContentName;
this.windowBackGroundColor = windowBackGroundColor;
this.windowInitPostion = windowInitPostion;
this.windowInitSize = windowInitSize;
this.windowNavHeight = windowNavHeight;
this.windowTabbarHeight = windowTabbarHeight;
}
}
export class FloatWindowUtil {
private windowOptions: FlowWindowOptions;
constructor(windowOptions: FlowWindowOptions) {
this.windowOptions = windowOptions;
}
// 定义windowClass变量,用来接收创建的悬浮窗
// 自定义创建悬浮窗方法
createFloatWindow() {
if (this.windowOptions==undefined){
console.error('windowOptions 不能为空');
return
}
// 窗口类型设置为window.WindowType.TYPE_FLOAT
// 创建悬浮窗
this.windowOptions.windowStage.createSubWindow(this.windowOptions.windowName, (err, win) => {
if (err.code) {
console.error('Failed to create the floatWindow. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in creating the floatWindow. Data: ' + JSON.stringify(win));
let window_w = StyleConstants.WINDOW_SIZE.width as number;
let window_h = StyleConstants.WINDOW_SIZE.height as number;
if (this.windowOptions.windowInitSize) {
if (this.windowOptions.windowInitSize.width <= 0) {
console.error('window 宽度不能设置为0,使用默认宽度 ');
}else if (this.windowOptions.windowInitSize.width + window_w >display.getDefaultDisplaySync().width) {
console.error('window 宽度设置太大,使用默认宽度 ');
}else {
window_w = this.windowOptions.windowInitSize.width;
}
if (this.windowOptions.windowInitSize.height <= 0) {
console.error('window 高度不能设置为0,使用默认高度 ');
}else if (this.windowOptions.windowInitSize.height + window_h >display.getDefaultDisplaySync().height) {
console.error('window 高度设置太大,使用默认高度');
}else {
window_h = this.windowOptions.windowInitSize.height;
}
}
let positionY :number = StyleConstants.WINDOW_POSTION.y as number;
if (this.windowOptions.windowInitPostion){
if (this.windowOptions.windowInitPostion.y) {
positionY = this.windowOptions.windowInitPostion.y as number
}
}
let navHeight: number = StyleConstants.WINDOW_NAVGATION_H;
if (this.windowOptions.windowNavHeight){
if (navHeight > StyleConstants.WINDOW_NAVGATION_H * 2) {
navHeight = StyleConstants.WINDOW_NAVGATION_H;
}else {
navHeight = this.windowOptions.windowNavHeight;
}
}
if (positionY < navHeight){
console.info('window放在导航上了,更新为导航底部开始');
positionY = navHeight;
}
let tabbarHeight: number = StyleConstants.WINDOW_BOTTOM_H;
if (this.windowOptions.windowTabbarHeight){
if (tabbarHeight > StyleConstants.WINDOW_NAVGATION_H * 2) {
navHeight = StyleConstants.WINDOW_NAVGATION_H;
}else {
tabbarHeight = this.windowOptions.windowTabbarHeight;
}
}
if (vp2px(positionY) + vp2px(window_h) + vp2px(tabbarHeight)>display.getDefaultDisplaySync().height){
console.error('windowInitPostion 超过屏幕范围 ');
positionY = display.getDefaultDisplaySync().height - window_h - tabbarHeight;
}
let positionX :number = StyleConstants.WINDOW_POSTION.x as number;
if (this.windowOptions.windowInitPostion){
if (this.windowOptions.windowInitPostion.x && this.windowOptions.windowInitPostion.x>0) {
positionX = this.windowOptions.windowInitPostion.x as number
}
}
if (vp2px(positionX)+ vp2px(window_w)>display.getDefaultDisplaySync().width){
console.error('windowInitPostion 超过屏幕范围 ');
positionX = display.getDefaultDisplaySync().width
}
// 设置悬浮窗位置
win.moveWindowTo(display.getDefaultDisplaySync().width - vp2px(positionX), vp2px(positionY), (err) => {
if (err.code) {
console.error('Failed to move the window. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in moving the window.');
});
// 设置悬浮窗大小
win.resize(window_w, window_h, (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.');
});
// 为悬浮窗加载页面内容,这里可以设置在main_pages.json中配置的页面
win.setUIContent(this.windowOptions.windowShowInContentName, (err: BusinessError) => {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
win.setWindowBackgroundColor(this.windowOptions.windowBackGroundColor?this.windowOptions.windowBackGroundColor:'#12ffff00')
console.info('Succeeded in loading the content.');
// 显示悬浮窗。
win.showWindow((err: BusinessError) => {
if (err.code) {
console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in showing the window.');
});
});
});
}
// 自定义销毁悬浮窗方法
destroyFloatWindow(windowName:string) {
// 用windowClass调用destroyWindow销毁悬浮窗
window.findWindow(windowName).destroyWindow((err) => {
if (err.code) {
console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in destroying the window.');
});
}
}
// export default new FloatWindowUtil(AppStorage.get('windowStage') as window.WindowStage,'1'})
export default class StyleConstants {
static readonly WINDOW_PAD: number = 5
static readonly WINDOW_BOTTOM_H: number = 60
static readonly WINDOW_NAVGATION_H: number = 60
static readonly WINDOW_SIZE: Size = ({width:40,height:40})
static readonly WINDOW_POSTION: Position = ({x:40,y:600})
}
使用方法:
@State windowStage: window.WindowStage = AppStorage.get('windowStage') as window.WindowStage;
private windowName: string = 'floatWindow'
private floatWindow?: FloatWindowUtil = undefined
aboutToAppear(): void {
let floatWindowOptions:FlowWindowOptions = new FlowWindowOptions(this.windowStage,this.windowName,'pages/TotalTimePage',undefined,undefined,undefined,60,60);
let floatWindow: FloatWindowUtil = new FloatWindowUtil(floatWindowOptions);
floatWindow.createFloatWindow();
this.floatWindow = floatWindow;
AppStorage.setOrCreate('timeFloatWindowName', this.windowName);
}
参数为undefined的都是默认大小,默认背景色。
效果图如下: