鸿蒙HarmonyOS实战-窗口管理
前言
窗口管理是指计算机操作系统中管理和控制窗口的一种机制。窗口管理器负责处理窗口的创建、关闭、移动、调整大小等操作,并且决定窗口的位置、层级、是否可见、是否接收用户输入等属性。窗口管理器还负责绘制窗口的外观和边框,并提供用户与窗口交互的方式,如鼠标点击、键盘输入等。窗口管理器可以通过图形用户界面(GUI)或命令行界面(CLI)来实现。不同操作系统和桌面环境提供不同的窗口管理器,如Windows系统下的Windows窗口管理器、macOS系统下的Aqua窗口管理器、Linux系统下的X窗口系统等。窗口管理的目的是提供用户友好的界面,方便用户进行多任务操作和窗口间的切换和管理。
一、窗口管理
1.窗口开发概述
1.1 窗口模块的定义
窗口模块是在同一块物理屏幕上提供多个应用界面显示和交互的机制。对应用开发者而言,窗口模块是一个重要的工具,它允许他们创建具有界面的应用程序,并提供了界面显示和交互的能力。通过窗口模块,开发者可以方便地管理窗口的创建、展示和关闭,并可以对窗口进行调整和布局,以满足用户的需求。
而对终端用户而言,窗口模块提供了一种控制应用界面的方式。用户可以通过窗口模块来切换和控制不同应用程序的窗口,使得他们能够同时在屏幕上显示多个应用界面,并能够在这些界面之间进行交互和操作。窗口模块还提供了一些常用的窗口管理功能,如最小化、最大化、拖拽等,以方便用户进行界面控制。
从整个操作系统的角度来看,窗口模块提供了对不同应用界面的组织和管理逻辑。它负责分配和管理屏幕上的空间,确保应用程序的窗口能够正确显示,并且能够适应不同屏幕大小和分辨率的设备。窗口模块还负责处理窗口之间的交互和通信,以保证应用程序的正常运行。
窗口模块在软件开发中扮演着重要角色,它不仅为应用开发者提供了界面显示和交互能力,也为终端用户提供了控制应用界面的方式,同时为整个操作系统提供了对应用界面的组织和管理逻辑。
1.2 窗口模块的用途

通过窗口模块的上述职责,HarmonyOS能够提供强大的窗口管理功能,实现应用界面的显示、交互和动效。开发者可以使用窗口对象加载UI界面,定义窗口的显示关系和位置属性,以及控制窗口的触摸和焦点状态。这使得应用程序在同一块物理屏幕上能够提供多个应用界面的显示和交互机制,为终端用户提供了更丰富的控制应用界面的方式。整个操作系统也能够通过窗口模块进行不同应用界面的组织和管理逻辑,实现多任务的同时进行。
1.3 基本概念
在 HarmonyOS 中,窗口模块将窗口界面分为系统窗口和应用窗口两种基本类型。系统窗口是完成系统特定功能的窗口,例如音量条、壁纸、通知栏、状态栏、导航栏等。这些窗口的设计旨在提供系统级别的功能和信息,以便用户可以方便地访问和管理。
与系统窗口相对应的是应用窗口,这些窗口与应用的显示相关。根据窗口内容的不同,应用窗口可以进一步分为应用主窗口和应用子窗口两种类型。
应用主窗口主要用于显示应用的界面,它是应用的核心窗口。当用户通过任务管理界面切换到应用时,应用主窗口将被显示出来,让用户可以直接与应用进行交互。
应用子窗口则是用于显示应用的弹窗、悬浮窗等辅助窗口。与应用主窗口不同的是,应用子窗口不会在任务管理界面显示。它们的生命周期与应用主窗口相同,即当应用主窗口销毁时,相关的应用子窗口也会被销毁。
通过这种窗口模块的划分和设计,HarmonyOS 可以更好地管理和控制窗口的显示和交互,为用户提供更加流畅和便捷的操作体验。无论是系统窗口还是应用窗口,它们都具有不同的功能和用途,相互配合,共同构建了丰富多样的窗口界面。
1.4 实现原理
HarmonyOS窗口管理的实现原理主要依赖于以下几点:
基于面向对象的窗口管理:HarmonyOS使用面向对象的方式来管理窗口。每个窗口都是一个对象,具有自己的属性和方法。窗口管理器负责创建、销毁、调度和管理这些窗口对象。
窗口栈管理:HarmonyOS采用了窗口栈的方式来管理窗口。窗口栈是一个存储窗口对象的有序集合,栈的顶部是当前正在显示的窗口。当用户打开一个新的窗口时,它会被添加到栈的顶部,而当窗口被关闭时,它会从栈中移除。通过管理窗口栈,窗口管理器可以实现窗口的切换和管理。
窗口调度算法:窗口管理器使用调度算法来确定当前应该显示哪个窗口。常见的调度算法有先进先出(FIFO)、最近最少使用(LRU)等。调度算法可以根据窗口的优先级、用户行为和系统资源等因素来决定窗口的调度顺序。
窗口布局管理:HarmonyOS的窗口管理还包括窗口的布局管理。窗口布局管理器负责确定窗口的大小、位置和布局方式,以确保窗口在屏幕上正确显示。布局管理器可以根据窗口的属性、屏幕大小和用户设置等因素来动态调整窗口的布局。
1.5 约束与限制
应用主窗口与子窗口存在大小限制,宽度范围:[320, 2560],高度范围:[240, 2560],单位为vp。
2.管理应用窗口
2.1 基本概念
️2.1.1 窗口沉浸式能力
窗口沉浸式能力是指一个窗口应用程序能够将用户的注意力完全吸引到其界面上,并使用户对其他应用程序和操作系统的界面感知降到最低的能力。窗口沉浸式能力通常通过以下几个方面来实现:
使用全屏模式:窗口应用程序可以将自己的界面展示在整个屏幕上,从而将其他应用程序和操作系统的界面隐藏起来,使用户更加专注于当前应用程序的内容。
最小化视觉干扰:窗口应用程序可以通过设计简洁、优雅的界面,避免不必要的视觉元素和干扰,从而提供一个更加清晰和集中注意力的界面。
提供沉浸式内容:窗口应用程序可以提供各种吸引人的内容,如高质量的图像、音频和视频,以吸引用户的注意力并使其完全投入到应用程序的体验中。
屏蔽外部干扰:窗口应用程序可以屏蔽或减少来自其他应用程序和操作系统的通知和提示等外部干扰,从而让用户在使用应用程序时不受打扰。
窗口沉浸式能力的目的是为了提供一种更加沉浸和集中注意力的用户体验,使用户能够更好地享受和使用窗口应用程序的功能和内容。
️2.1.2 悬浮窗
悬浮窗是一种浮动在屏幕上方的小窗口,可以在其他应用程序之上展示信息或功能。它可以提供快速访问或查看特定内容,而无需离开当前应用程序。悬浮窗通常可以被拖动、调整大小或关闭。在移动设备上,悬浮窗常用于显示通知、快捷操作或其他实用工具。
2.3 场景介绍
️2.3.1 设置应用主窗口
主窗口的"是否可触"属性是指能否通过触摸屏与用户进行交互。如果主窗口的"是否可触"属性为True,则用户可以通过触摸屏对主窗口进行操作,例如点击按钮、滑动界面等。如果主窗口的"是否可触"属性为False,则用户无法通过触摸屏进行交互,只能使用其他输入设备(如鼠标)进行操作。通常情况下,移动设备(如手机、平板电脑)上的主窗口会设置为可触摸,而桌面电脑上的主窗口可能会设置为不可触摸。
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
// 1.获取应用主窗口。
let windowClass = null;
windowStage.getMainWindow((err, data) => {
if (err.code) {
console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
return;
}
windowClass = data;
console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data));
// 2.设置主窗口属性。以设置"是否可触"属性为例。
let isTouchable = true;
windowClass.setWindowTouchable(isTouchable, (err) => {
if (err.code) {
console.error('Failed to set the window to be touchable. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in setting the window to be touchable.');
})
})
// 3.为主窗口加载对应的目标页面。
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}
️2.3.2 设置应用子窗口
应用子窗口是指在一个主窗口或父窗口之内创建一个较小的窗口,用于显示其他相关的内容或功能。子窗口通常是独立于主窗口的,可以拖动、最小化、最大化和关闭。应用子窗口可以提供更好的用户体验,将相关的功能和信息集中在一起,并且可以在主窗口内方便地切换和操作。
应用子窗口常见的应用场景包括:
弹出式对话框:用于显示警告、提示、确认等信息,请求用户的输入或进行操作确认。
工具窗口:用于显示一些辅助工具,例如调色板、图层面板等,在用户需要时进行操作。
标签页:用于在主窗口内切换和显示不同的内容,例如浏览器的多个标签页。
拆分窗口:将主窗口分割成多个子窗口,用于同时显示多个相关的内容,例如文本编辑器的分屏编辑功能。
应用子窗口可以提高用户的操作效率和便利性,使界面更加灵活和功能更加丰富。但在设计和使用时需要注意合理使用,避免过多的窗口导致用户的混乱和困惑。
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.子窗口创建成功后,设置子窗口的位置、大小及相关属性等。
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.');
});
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();
}
};
️2.3.3 体验窗口沉浸式能力
概念上面有介绍,就不多说了。
import UIAbility from '@ohos.app.ability.UIAbility';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage) {
// 1.获取应用主窗口。
let windowClass = null;
windowStage.getMainWindow((err, data) => {
if (err.code) {
console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
return;
}
windowClass = data;
console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data));
// 2.实现沉浸式效果:设置导航栏、状态栏不显示。
let names = [];
windowClass.setWindowSystemBarEnable(names, (err) => {
if (err.code) {
console.error('Failed to set the system bar to be visible. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in setting the system bar to be visible.');
});
})
// 3.为沉浸式窗口加载对应的目标页面。
windowStage.loadContent("pages/page2", (err) => {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in loading the content.');
});
}
};

️2.3.4 设置悬浮窗
概念上面有介绍,就不多说了。
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage) {
// 1.创建悬浮窗。
let windowClass = null;
let config = {name: "floatWindow", windowType: window.WindowType.TYPE_FLOAT, ctx: this.context};
window.createWindow(config, (err, data) => {
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(data));
windowClass = data;
// 2.悬浮窗窗口创建成功后,设置悬浮窗的位置、大小及相关属性等。
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.');
});
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.为悬浮窗加载对应的目标页面。
windowClass.setUIContent("pages/page4", (err) => {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in loading the content.');
// 3.显示悬浮窗。
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.');
});
});
// 4.销毁悬浮窗。当不再需要悬浮窗时,可根据具体实现逻辑,使用destroy对其进行销毁。
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.');
});
});
}
};
写在最后
- 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing,不定期分享原创知识。
- 更多鸿蒙最新技术知识点,请关注作者博客:https://t.doruo.cn/14DjR1rEY

鸿蒙HarmonyOS实战-窗口管理的更多相关文章
- Moom for mac 最棒的窗口管理软件
win7下,鼠标拖动窗口向左.右,两个窗口就在一个桌面上平分秋色了 mac下只能使用三只爪向上的手势查看当前桌面运行的程序,或者三只爪左右滑动查看全屏显示的其他程序,有时候一边看书一边敲代码很不方便 ...
- Emacs 之窗口管理
// */ // ]]> Emacs 之窗口管理 Table of Contents 1. Emacs 窗口相关 1.1. Emacs 里调整 window 大小 1.2. Emacs winn ...
- Visio 2007/2010 左侧"形状"窗口管理
Visio 2007/2010 左侧"形状"窗口管理 Visio 打开后,通常窗口左侧会有一个“形状”面板,我们可以方便地从中选择需要的形状.有时为了获得更大的版面空间或者不小心关 ...
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...
- OpenGL的GLUT事件处理(Event Processing)窗口管理(Window Management)函数[转]
GLUT事件处理(Event Processing)窗口管理(Window Management)函数 void glutMainLoop(void) 让glut程序进入事件循环.在一个glut程序中 ...
- Android 核心分析之十三Android GWES之Android窗口管理
Android GWES之Android窗口管理1基本构架原理 Android的窗口管理是C/S模式的.Android中的Window是表示Top Level等顶级窗口的概念.DecorView是Wi ...
- Android 核心分析之十二Android GEWS窗口管理之基本架构原理
Android GWES之窗口管理之基本构架原理 Android的窗口管理是C/S模式的.Android中的Window是表示Top Level等顶级窗口的概念.DecorView是Window的To ...
- Mac窗口管理管理软件SizeUp
一.SizeUp 是一款 Mac窗口管理管理软件.借助SizeUp,可以快速变化窗口大小(最大化.最小化),可以快速切换窗口的不同位置. 尤其在双显示器,更是扮演者方便.高效.好用的角色,提供了快速切 ...
- Android 窗口管理
一.概述 在Android系统中,从设计的角度来看,窗口管理系统是基于C/S模式的.整个窗口系统分为服务端和客户端两大部分,客户端负责请求创建窗口和使用窗口,服务端完成窗口的维护,窗口显示等. 在Cl ...
- Android 之 Window、WindowManager 与窗口管理
其实在android中真正展示给用户的是window和view,activity在android中所其的作用主要是处理一些逻辑问题,比如生命周期的管理.建立窗口等.在android中,窗口的管理还是比 ...
随机推荐
- Redis 数据类型list以及使用场景
简介: Redis 数据类型list以及使用场景 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序list类型:保存多 ...
- ZooKeeper 在阿里巴巴的服务形态演进
简介: 本文将给大家介绍下 ZooKeeper 的最佳实践场景,归为了 3 类,分别是:微服务领域,代表的集成产品是 Dubbo/SpringCloud:大数据领域,代表的集成产品是 Flink/Hb ...
- 从托管到原生,MPP架构数据仓库的云原生实践
简介:本文介绍了云原生数据仓库产品AnalyticDB PostgreSQL从Cloud-Hosted到Cloud-Native的演进探索,探讨为了实现真正的资源池化和灵活售卖的底层设计和思考,涵盖 ...
- 龙蜥利器:系统运维工具 SysAK的云上应用性能诊断 | 龙蜥技术
简介:本文从大量的性能诊断实践出发,来介绍 SysAK 在性能诊断上的方法论及相关工具. 文/张毅:系统运维SIG核心成员.SysAK 项目负责人:毛文安:系统运维 SIG 负责人. 系统运维既 ...
- 网不好怎么办?TLS握手带宽直降80%,BabaSSL是怎么做到的?| 龙蜥技术
简介:为了保障数据的安全性,客户端会先和服务器进行 TLS 握手,有什么办法可以减少 TLS 握手的带宽消耗呢? 编者按:BabaSSL 是一款开源的密码库产品,在 GitHub 和龙蜥社区开源,并 ...
- 2018-11-14-git无法pull仓库refusing-to-merge-unrelated-histories
title author date CreateTime categories git无法pull仓库refusing to merge unrelated histories lindexi 201 ...
- 8.k8s之调动pod到指定节点与创建多容器pod并查找pod日志
官方文档:将pod分配给节点题目1:调度pod到指定节点 设置配置环境kubectl config use-context k8s 按如下要求创建并调度一个pod: - 名称:nginx-kusc00 ...
- RT-Thread 运行时常见错误
一.空线程栈较小 现象: 现象一: 现象二: 原因: 从RT-Thread文章中心可知,空闲线程是不能被挂起的,官方文档说明如下图所示: 注意:必须保证空闲线程的栈空间足够,否则空闲线程内存溢出后,也 ...
- 【python爬虫案例】用python爬取百度的搜索结果!2023.3发布
目录 一.爬取目标 二.展示结果数据 三.编写爬虫代码 3.1 请求头和cookie 3.2 分析请求地址 3.3 分析页面元素 3.4 获取真实地址 3.5 保存结果数据 四.同步讲解视频 五.附完 ...
- typescript基础知识汇总
JavaScript中所有事物(字符串.数值.数组.函数)都是对象,都有属性和方法.1.用函数定义对象,然后new对象实例.2.用Object定义并创建对象实例var o = new Object(t ...