HarmonyOS Next开发学习手册——窗口管理

打印 上一主题 下一主题

主题 819|帖子 819|积分 2457

窗口模块的界说

窗口模块用于在同一块物理屏幕上,提供多个应用界面表现、交互的机制。


  • 对应用开发者而言,窗口模块提供了界面表现和交互本事。
  • 对终端用户而言,窗口模块提供了控制应用界面的方式。
  • 对整个操作系统而言,窗口模块提供了差别应用界面的构造管理逻辑。
窗口模块的用途

在HarmonyOS中,窗口模块重要负责以下职责:


  • 提供应用和系统界面的窗口对象。 应用开发者通过窗口加载UI界面,实现界面表现功能。
  • 构造差别窗口的表现关系,即维护差别窗口间的叠加层次和位置属性。 应用和系统的窗口具有多种范例,差别范例的窗口具有差别的默认位置和叠加层次(Z轴高度)。同时,用户操作也可以在肯定范围内对窗口的位置和叠加层次举行调整。
  • 提供窗口装饰。窗口装饰指窗口标题栏和窗口边框。 窗口标题栏通常包括窗口最大化、最小化及关闭按钮等界面元素,具有默认的点击行为,方便用户举行操作;窗口边框则方便用户对窗口举行拖拽缩放等行为。窗口装饰是系统的默认行为,开发者可选择启用/禁用,无需关注UI代码层面的实现。
  • 提供窗口动效。 在窗口表现、隐蔽及窗口间切换时,窗口模块通常会添加动画效果,以使各个交互过程更加连贯流畅。在HarmonyOS中,应用窗口的动效为默认行为,不必要开发者举行设置或者修改。
  • 指导输入事件分发。 即根据当前窗口的状态或焦点,举行事件的分发。触摸和鼠标事件根据窗口的位置和尺寸举行分发,而键盘事件会被分发至焦点窗口。应用开发者可以通过窗口模块提供的接口设置窗口是否可以触摸和是否可以获焦。
根本概念

窗口范例

HarmonyOS的窗口模块将窗口界面分为系统窗口、应用窗口两种根本范例。


  • 系统窗口:系统窗口指完成系统特定功能的窗口。如音量条、壁纸、通知栏、状态栏、导航栏等。
  • 应用窗口:应用窗口区别于系统窗口,指与应用表现相关的窗口。根据表现内容的差别,应用窗口又分为应用主窗口、应用子窗口两种范例。

    • 应用主窗口:应用主窗口用于表现应用界面,会在"使命管理界面"表现。
    • 应用子窗口:应用子窗口用于表现应用的弹窗、悬浮窗等辅助窗口,不会在"使命管理界面"表现。应用子窗口的生命周期跟随应用主窗口。

应用窗口模式

应用窗口模式指应用主窗口启动时的表现方式。HarmonyOS目前支持全屏、分屏、自由窗口三种应用窗口模式。这种对多种应用窗口模式的支持本事,也称为操作系统的“多窗口本事”。


  • 全屏:应用主窗口启动时铺满整个屏幕。
  • 分屏:应用主窗口启动时占据屏幕的某个部分,当前支持二分屏。两个分屏窗口之间具有分界线,可通过拖拽分界线调整两个部分的窗口尺寸。
  • 自由窗口:自由窗口的大小和位置可自由改变。同一个屏幕上可同时表现多个自由窗口,这些自由窗口按照打开或者获取焦点的序次在Z轴排布。当自由窗口被点击或触摸时,将导致其Z轴高度提拔,并获取焦点。

实现原理

当前窗口的实现和开发与应用开发模子相关联,差别模子下的接口功能略有区别。当前应用开发模子分为FA模子和Stage模子。
两个模子的整体架构和设计思想,详见[应用模子解读] 。
针对窗口开发,推荐利用Stage模子举行相关开发。
约束与限制



  • 在FA模子下,不支持系统窗口的相关开发。
  • 应用主窗口与子窗口存在大小限制,宽度范围:[320, 2560],高度范围:[240, 2560],单元为vp。
  • 系统窗口存在大小限制,宽度范围:[0, 2560],高度范围:[0, 2560],单元为vp。
管理应用窗口(Stage模子)

根本概念



  • 窗口沉醉式本事:指对状态栏、导航栏等系统窗口举行控制,减少状态栏导航栏等系统界面的突兀感,从而利用户得到最佳体验的本事。
    沉醉式本事只在应用主窗口作为全屏窗口时生效。通常环境下,应用子窗口(弹窗、悬浮窗口等辅助窗口)和处于自由窗口下的应用主窗口无法利用沉醉式本事。
  • 悬浮窗:全局悬浮窗口是一种特殊的应用窗口,具备在应用主窗口和对应Ability退至后台后仍旧可以在前台表现的本事。
    悬浮窗口可以用于应用退至后台后,利用小窗继续播放视频,或者为特定的应用创建悬浮球等快速入口。应用在创建悬浮窗口前,必要申请对应的权限。
场景介绍

在Stage模子下,管理应用窗口的典型场景有:


  • 设置应用主窗口属性及目标页面
  • 设置应用子窗口属性及目标页面
  • 体验窗口沉醉式本事
  • 设置悬浮窗
  • 监听窗口不可交互与可交互事件
以下分别介绍具体开发方式。
接口说明

上述场景涉及的常用接口如下表所示。
实例名接口名描述WindowStagegetMainWindow(callback: AsyncCallback): void获取WindowStage实例下的主窗口。
此接口仅可在Stage模子下利用。WindowStageloadContent(path: string, callback: AsyncCallback): void为当前WindowStage的主窗口加载具体页面。
其中path为要加载到窗口中的页面内容的路径,该路径需添加到工程的main_pages.json文件中。
此接口仅可在Stage模子下利用。WindowStagecreateSubWindow(name: string, callback: AsyncCallback): void创建子窗口。 此接口仅可在Stage模子下利用。WindowStageon(type: ‘windowStageEvent’, callback: Callback): void开启WindowStage生命周期变化的监听。
此接口仅可在Stage模子下利用。window静态方法createWindow(config: Configuration, callback: AsyncCallback): void创建子窗口或者系统窗口。
-config:创建窗口时的参数。WindowsetUIContent(path: string, callback: AsyncCallback): void根据当前工程中某个页面的路径为窗口加载具体的页面内容。
其中path为要加载到窗口中的页面内容的路径,在Stage模子下该路径需添加到工程的main_pages.json文件中。WindowsetWindowBrightness(brightness: number, callback: AsyncCallback): void设置屏幕亮度值。WindowsetWindowTouchable(isTouchable: boolean, callback: AsyncCallback): void设置窗口是否为可触状态。WindowmoveWindowTo(x: number, y: number, callback: AsyncCallback): void移动当前窗口位置。Windowresize(width: number, height: number, callback: AsyncCallback): void改变当前窗口大小。WindowsetWindowLayoutFullScreen(isLayoutFullScreen: boolean, callback: AsyncCallback): void设置窗口布局是否为全屏布局。WindowsetWindowSystemBarEnable(names: Array<‘status’‘navigation’>): PromiseWindowsetWindowSystemBarProperties(systemBarProperties: SystemBarProperties, callback: AsyncCallback): void设置窗口内导航栏、状态栏属性。
systemBarProperties:导航栏、状态栏的属性聚集。WindowshowWindow(callback: AsyncCallback): void表现当前窗口。Windowon(type: ‘touchOutside’, callback: Callback): void开启本窗口区域外的点击事件的监听。WindowdestroyWindow(callback: AsyncCallback): void烧毁当前窗口。 设置应用主窗口

在Stage模子下,应用主窗口由UIAbility创建并维护生命周期。在UIAbility的onWindowStageCreate回调中,通过WindowStage获取应用主窗口,即可对其举行属性设置等操作。还可以在应用配置文件中设置应用主窗口的属性,如最大窗口宽度maxWindowWidth等 。
开发步调


  • 获取应用主窗口。
通过getMainWindow接口获取应用主窗口。

  • 设置主窗口属性。
可设置主窗口的背景色、亮度值、是否可触等多个属性,开发者可根据必要选择对应的接口。本示例以设置“是否可触”属性为例。

  • 为主窗口加载对应的目标页面。
    通过loadContent接口加载主窗口的目标页面。
  1. import { UIAbility } from '@kit.AbilityKit';
  2. import { window } from '@kit.ArkUI';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. export default class EntryAbility extends UIAbility {
  5.   onWindowStageCreate(windowStage: window.WindowStage) {
  6.     // 1.获取应用主窗口。
  7.     let windowClass: window.Window | null = null;
  8.     windowStage.getMainWindow((err: BusinessError, data) => {
  9.       let errCode: number = err.code;
  10.       if (errCode) {
  11.         console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
  12.         return;
  13.       }
  14.       windowClass = data;
  15.       console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data));
  16.       // 2.设置主窗口属性。以设置"是否可触"属性为例。
  17.       let isTouchable: boolean = true;
  18.       windowClass.setWindowTouchable(isTouchable, (err: BusinessError) => {
  19.         let errCode: number = err.code;
  20.         if (errCode) {
  21.           console.error('Failed to set the window to be touchable. Cause:' + JSON.stringify(err));
  22.           return;
  23.         }
  24.         console.info('Succeeded in setting the window to be touchable.');
  25.       })
  26.     })
  27.     // 3.为主窗口加载对应的目标页面。
  28.     windowStage.loadContent("pages/page2", (err: BusinessError) => {
  29.       let errCode: number = err.code;
  30.       if (errCode) {
  31.         console.error('Failed to load the content. Cause:' + JSON.stringify(err));
  32.         return;
  33.       }
  34.       console.info('Succeeded in loading the content.');
  35.     });
  36.   }
  37. };
复制代码
设置应用子窗口

开发者可以按需创建应用子窗口,如弹窗等,并对其举行属性设置等操作。
开发步调


  • 创建应用子窗口。
通过createSubWindow接口创建应用子窗口。

  • 设置子窗口属性。
子窗口创建成功后,可以改变其大小、位置等,还可以根据应用必要设置窗口背景色、亮度等属性。

  • 加载表现子窗口的具体内容。
通过setUIContent和showWindow接口加载表现子窗口的具体内容。

  • 烧毁子窗口。
当不再必要某些子窗口时,可根据具体实现逻辑,利用destroyWindow接口烧毁子窗口。
直接在onWindowStageCreate里面创建子窗口的整体示例代码如下:
  1. import { UIAbility } from '@kit.AbilityKit';
  2. import { window } from '@kit.ArkUI';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. let windowStage_: window.WindowStage | null = null;
  5. let sub_windowClass: window.Window | null = null;
  6. export default class EntryAbility extends UIAbility {
  7.   showSubWindow() {
  8.     // 1.创建应用子窗口。
  9.     if (windowStage_ == null) {
  10.       console.error('Failed to create the subwindow. Cause: windowStage_ is null');
  11.     }
  12.     else {
  13.       windowStage_.createSubWindow("mySubWindow", (err: BusinessError, data) => {
  14.         let errCode: number = err.code;
  15.         if (errCode) {
  16.           console.error('Failed to create the subwindow. Cause: ' + JSON.stringify(err));
  17.           return;
  18.         }
  19.         sub_windowClass = data;
  20.         console.info('Succeeded in creating the subwindow. Data: ' + JSON.stringify(data));
  21.         // 2.子窗口创建成功后,设置子窗口的位置、大小及相关属性等。
  22.         sub_windowClass.moveWindowTo(300, 300, (err: BusinessError) => {
  23.           let errCode: number = err.code;
  24.           if (errCode) {
  25.             console.error('Failed to move the window. Cause:' + JSON.stringify(err));
  26.             return;
  27.           }
  28.           console.info('Succeeded in moving the window.');
  29.         });
  30.         sub_windowClass.resize(500, 500, (err: BusinessError) => {
  31.           let errCode: number = err.code;
  32.           if (errCode) {
  33.             console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
  34.             return;
  35.           }
  36.           console.info('Succeeded in changing the window size.');
  37.         });
  38.         // 3.为子窗口加载对应的目标页面。
  39.         sub_windowClass.setUIContent("pages/page3", (err: BusinessError) => {
  40.           let errCode: number = err.code;
  41.           if (errCode) {
  42.             console.error('Failed to load the content. Cause:' + JSON.stringify(err));
  43.             return;
  44.           }
  45.           console.info('Succeeded in loading the content.');
  46.           // 3.显示子窗口。
  47.           (sub_windowClass as window.Window).showWindow((err: BusinessError) => {
  48.             let errCode: number = err.code;
  49.             if (errCode) {
  50.               console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
  51.               return;
  52.             }
  53.             console.info('Succeeded in showing the window.');
  54.           });
  55.         });
  56.       })
  57.     }
  58.   }
  59.   destroySubWindow() {
  60.     // 4.销毁子窗口。当不再需要子窗口时,可根据具体实现逻辑,使用destroy对其进行销毁。
  61.     (sub_windowClass as window.Window).destroyWindow((err: BusinessError) => {
  62.       let errCode: number = err.code;
  63.       if (errCode) {
  64.         console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
  65.         return;
  66.       }
  67.       console.info('Succeeded in destroying the window.');
  68.     });
  69.   }
  70.   onWindowStageCreate(windowStage: window.WindowStage) {
  71.     windowStage_ = windowStage;
  72.     // 开发者可以在适当的时机,如主窗口上按钮点击事件等,创建子窗口。并不一定需要在onWindowStageCreate调用,这里仅作展示
  73.     this.showSubWindow();
  74.   }
  75.   onWindowStageDestroy() {
  76.     // 开发者可以在适当的时机,如子窗口上点击关闭按钮等,销毁子窗口。并不一定需要在onWindowStageDestroy调用,这里仅作展示
  77.     this.destroySubWindow();
  78.   }
  79. };
复制代码
别的,也可以在某个page页面通过点击按钮创建子窗口,整体示例代码如下:
  1. // EntryAbility.ets
  2. onWindowStageCreate(windowStage: window.WindowStage) {
  3.   windowStage.loadContent('pages/Index', (err) => {
  4.     if (err.code) {
  5.       console.error('Failed to load the content. Cause:' + JSON.stringify(err));
  6.       return;
  7.     }
  8.     console.info('Succeeded in loading the content.');
  9.   })
  10.   // 给Index页面传递windowStage
  11.   AppStorage.setOrCreate('windowStage', windowStage);
  12. }
复制代码

  1. // Index.ets
  2. import { window } from '@kit.ArkUI';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. let windowStage_: window.WindowStage | undefined = undefined;
  5. let sub_windowClass: window.Window | undefined = undefined;
  6. @Entry
  7. @Component
  8. struct Index {
  9.   @State message: string = 'Hello World';
  10.   private CreateSubWindow(){
  11.     // 获取windowStage
  12.     windowStage_ = AppStorage.get('windowStage');
  13.     // 1.创建应用子窗口。
  14.     if (windowStage_ == null) {
  15.       console.error('Failed to create the subwindow. Cause: windowStage_ is null');
  16.     }
  17.     else {
  18.       windowStage_.createSubWindow("mySubWindow", (err: BusinessError, data) => {
  19.         let errCode: number = err.code;
  20.         if (errCode) {
  21.           console.error('Failed to create the subwindow. Cause: ' + JSON.stringify(err));
  22.           return;
  23.         }
  24.         sub_windowClass = data;
  25.         console.info('Succeeded in creating the subwindow. Data: ' + JSON.stringify(data));
  26.         // 2.子窗口创建成功后,设置子窗口的位置、大小及相关属性等。
  27.         sub_windowClass.moveWindowTo(300, 300, (err: BusinessError) => {
  28.           let errCode: number = err.code;
  29.           if (errCode) {
  30.             console.error('Failed to move the window. Cause:' + JSON.stringify(err));
  31.             return;
  32.           }
  33.           console.info('Succeeded in moving the window.');
  34.         });
  35.         sub_windowClass.resize(500, 500, (err: BusinessError) => {
  36.           let errCode: number = err.code;
  37.           if (errCode) {
  38.             console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
  39.             return;
  40.           }
  41.           console.info('Succeeded in changing the window size.');
  42.         });
  43.         // 3.为子窗口加载对应的目标页面。
  44.         sub_windowClass.setUIContent("pages/subWindow", (err: BusinessError) => {
  45.           let errCode: number = err.code;
  46.           if (errCode) {
  47.             console.error('Failed to load the content. Cause:' + JSON.stringify(err));
  48.             return;
  49.           }
  50.           console.info('Succeeded in loading the content.');
  51.           // 3.显示子窗口。
  52.           (sub_windowClass as window.Window).showWindow((err: BusinessError) => {
  53.             let errCode: number = err.code;
  54.             if (errCode) {
  55.               console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
  56.               return;
  57.             }
  58.             console.info('Succeeded in showing the window.');
  59.           });
  60.         });
  61.       })
  62.     }
  63.   }
  64.   private destroySubWindow(){
  65.     // 4.销毁子窗口。当不再需要子窗口时,可根据具体实现逻辑,使用destroy对其进行销毁。
  66.     (sub_windowClass as window.Window).destroyWindow((err: BusinessError) => {
  67.       let errCode: number = err.code;
  68.       if (errCode) {
  69.         console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
  70.         return;
  71.       }
  72.       console.info('Succeeded in destroying the window.');
  73.     });
  74.   }
  75.   build() {
  76.     Row() {
  77.       Column() {
  78.         Text(this.message)
  79.           .fontSize(50)
  80.           .fontWeight(FontWeight.Bold)
  81.         Button(){
  82.           Text('CreateSubWindow')
  83.           .fontSize(24)
  84.           .fontWeight(FontWeight.Normal)
  85.         }.width(220).height(68)
  86.         .margin({left:10, top:60})
  87.         .onClick(() => {
  88.           this.CreateSubWindow()
  89.         })
  90.         Button(){
  91.           Text('destroySubWindow')
  92.           .fontSize(24)
  93.           .fontWeight(FontWeight.Normal)
  94.         }.width(220).height(68)
  95.         .margin({left:10, top:60})
  96.         .onClick(() => {
  97.           this.destroySubWindow()
  98.         })
  99.       }
  100.       .width('100%')
  101.     }
  102.     .height('100%')
  103.   }
  104. }
复制代码

  1. // subWindow.ets
  2. @Entry
  3. @Component
  4. struct SubWindow {
  5.   @State message: string = 'Hello subWindow';
  6.   build() {
  7.     Row() {
  8.       Column() {
  9.         Text(this.message)
  10.           .fontSize(50)
  11.           .fontWeight(FontWeight.Bold)
  12.       }
  13.       .width('100%')
  14.     }
  15.     .height('100%')
  16.   }
  17. }
复制代码
体验窗口沉醉式本事

在看视频、玩游戏等场景下,用户往往盼望隐蔽状态栏、导航栏等不必要的系统窗口,从而得到更佳的沉醉式体验。此时可以借助窗口沉醉式本事(窗口沉醉式本事都是针对应用主窗口而言的),到达预期效果。从API version 10开始,沉醉式窗口默认配置为全屏大小并由组件模块控制布局,状态栏、导航栏背景颜色为透明,文字颜色为黑色;应用窗口调用setWindowLayoutFullScreen接口,设置为true体现由组件模块控制忽略状态栏、导航栏的沉醉式全屏布局,设置为false体现由组件模块控制避让状态栏、导航栏的非沉醉式全屏布局。
   说明
当前沉醉式界面开发仅支持window级别的配置,暂不支持Page级别的配置。若有Page级别切换的必要,可以在页面生命周期开始,例如onPageShow中设置沉醉模式,然后在页面退出,例如onPageHide中恢复默认设置来实现。
  开发步调


  • 获取应用主窗口。
通过getMainWindow接口获取应用主窗口。

  • 实现沉醉式效果。有以下两种方式:


  • 方式一:应用主窗口为全屏窗口时,调用setWindowSystemBarEnable接口,设置导航栏、状态栏不表现,从而到达沉醉式效果。
  • 方式二:调用setWindowLayoutFullScreen接口,设置应用主窗口为全屏布局;然后调用setWindowSystemBarProperties接口,设置导航栏、状态栏的透明度、背景/文字颜色以及高亮图标等属性,使之保持与主窗口表现协调同等,从而到达沉醉式效果。

  • 加载表现沉醉式窗口的具体内容。
通过loadContent接口加载沉醉式窗口的具体内容。
  1. import { UIAbility } from '@kit.AbilityKit';
  2. import { window } from '@kit.ArkUI';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. export default class EntryAbility extends UIAbility {
  5.   onWindowStageCreate(windowStage: window.WindowStage) {
  6.     // 1.获取应用主窗口。
  7.     let windowClass: window.Window | null = null;
  8.     windowStage.getMainWindow((err: BusinessError, data) => {
  9.       let errCode: number = err.code;
  10.       if (errCode) {
  11.         console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
  12.         return;
  13.       }
  14.       windowClass = data;
  15.       console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data));
  16.       // 2.实现沉浸式效果。方式一:设置导航栏、状态栏不显示。
  17.       let names: Array<'status' | 'navigation'> = [];
  18.       windowClass.setWindowSystemBarEnable(names, (err: BusinessError) => {
  19.         let errCode: number = err.code;
  20.         if (errCode) {
  21.           console.error('Failed to set the system bar to be visible. Cause:' + JSON.stringify(err));
  22.           return;
  23.         }
  24.         console.info('Succeeded in setting the system bar to be visible.');
  25.       });
  26.       // 2.实现沉浸式效果。方式二:设置窗口为全屏布局,配合设置导航栏、状态栏的透明度、背景/文字颜色及高亮图标等属性,与主窗口显示保持协调一致。
  27.       let isLayoutFullScreen = true;
  28.       windowClass.setWindowLayoutFullScreen(isLayoutFullScreen, (err: BusinessError) => {
  29.         let errCode: number = err.code;
  30.         if (errCode) {
  31.           console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
  32.           return;
  33.         }
  34.         console.info('Succeeded in setting the window layout to full-screen mode.');
  35.       });
  36.       let sysBarProps: window.SystemBarProperties = {
  37.         statusBarColor: '#ff00ff',
  38.         navigationBarColor: '#00ff00',
  39.         // 以下两个属性从API Version 8开始支持
  40.         statusBarContentColor: '#ffffff',
  41.         navigationBarContentColor: '#ffffff'
  42.       };
  43.       windowClass.setWindowSystemBarProperties(sysBarProps, (err: BusinessError) => {
  44.         let errCode: number = err.code;
  45.         if (errCode) {
  46.           console.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err));
  47.           return;
  48.         }
  49.         console.info('Succeeded in setting the system bar properties.');
  50.       });
  51.     })
  52.     // 3.为沉浸式窗口加载对应的目标页面。
  53.     windowStage.loadContent("pages/page2", (err: BusinessError) => {
  54.       let errCode: number = err.code;
  55.       if (errCode) {
  56.         console.error('Failed to load the content. Cause:' + JSON.stringify(err));
  57.         return;
  58.       }
  59.       console.info('Succeeded in loading the content.');
  60.     });
  61.   }
  62. };
复制代码
##设置悬浮窗(受限开放)
悬浮窗可以在已有的使命基础上,创建一个始终在前台表现的窗口。即使创建悬浮窗的使命退至后台,悬浮窗仍旧可以在前台表现。通常悬浮窗位于所有应用窗口之上;开发者可以创建悬浮窗,并对悬浮窗举行属性设置等操作。
开发步调

条件条件: 创建WindowType.TYPE_FLOAT即悬浮窗范例的窗口,必要申请ohos.permission.SYSTEM_FLOAT_WINDOW权限,该权限为受控开放权限,仅符合 指定场景 的在2in1设备上的应用可申请该权限。
在其他设备或场景下,请利用画中画功能,利用方式参考:
   注意
  如果应用未在应用市场(AGC)申请相应的权限证书,却试图在配置文件中声明此类权限,将会导致应用安装失败。

  • 创建悬浮窗。
通过window.createWindow接口创建悬浮窗范例的窗口。

  • 对悬浮窗举行属性设置等操作。
悬浮窗窗口创建成功后,可以改变其大小、位置等,还可以根据应用必要设置悬浮窗背景色、亮度等属性。

  • 加载表现悬浮窗的具体内容。
通过setUIContent和showWindow接口加载表现悬浮窗的具体内容。

  • 烧毁悬浮窗。
当不再必要悬浮窗时,可根据具体实现逻辑,利用destroyWindow接口烧毁悬浮窗。
  1. import { UIAbility } from '@kit.AbilityKit';
  2. import { window } from '@kit.ArkUI';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. export default class EntryAbility extends UIAbility {
  5.   onWindowStageCreate(windowStage: window.WindowStage) {
  6.     // 1.创建悬浮窗。
  7.     let windowClass: window.Window | null = null;
  8.     let config: window.Configuration = {
  9.       name: "floatWindow", windowType: window.WindowType.TYPE_FLOAT, ctx: this.context
  10.     };
  11.     window.createWindow(config, (err: BusinessError, data) => {
  12.       let errCode: number = err.code;
  13.       if (errCode) {
  14.         console.error('Failed to create the floatWindow. Cause: ' + JSON.stringify(err));
  15.         return;
  16.       }
  17.       console.info('Succeeded in creating the floatWindow. Data: ' + JSON.stringify(data));
  18.       windowClass = data;
  19.       // 2.悬浮窗窗口创建成功后,设置悬浮窗的位置、大小及相关属性等。
  20.       windowClass.moveWindowTo(300, 300, (err: BusinessError) => {
  21.         let errCode: number = err.code;
  22.         if (errCode) {
  23.           console.error('Failed to move the window. Cause:' + JSON.stringify(err));
  24.           return;
  25.         }
  26.         console.info('Succeeded in moving the window.');
  27.       });
  28.       windowClass.resize(500, 500, (err: BusinessError) => {
  29.         let errCode: number = err.code;
  30.         if (errCode) {
  31.           console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
  32.           return;
  33.         }
  34.         console.info('Succeeded in changing the window size.');
  35.       });
  36.       // 3.为悬浮窗加载对应的目标页面。
  37.       windowClass.setUIContent("pages/page4", (err: BusinessError) => {
  38.         let errCode: number = err.code;
  39.         if (errCode) {
  40.           console.error('Failed to load the content. Cause:' + JSON.stringify(err));
  41.           return;
  42.         }
  43.         console.info('Succeeded in loading the content.');
  44.         // 3.显示悬浮窗。
  45.         (windowClass as window.Window).showWindow((err: BusinessError) => {
  46.           let errCode: number = err.code;
  47.           if (errCode) {
  48.             console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
  49.             return;
  50.           }
  51.           console.info('Succeeded in showing the window.');
  52.         });
  53.       });
  54.       // 4.销毁悬浮窗。当不再需要悬浮窗时,可根据具体实现逻辑,使用destroy对其进行销毁。
  55.       windowClass.destroyWindow((err: BusinessError) => {
  56.         let errCode: number = err.code;
  57.         if (errCode) {
  58.           console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
  59.           return;
  60.         }
  61.         console.info('Succeeded in destroying the window.');
  62.       });
  63.     });
  64.   }
  65. };
复制代码
监听窗口不可交互与可交互事件

应用在前台表现过程中可能会进入某些不可交互的场景,比力典型的是进入多使命界面。此时,对于一些应用可能必要选择停息某个与用户正在交互的业务,如视频类应用停息正在播放的视频或者相机停息预览流等。而当该应用从多使命又切回前台时,又变成了可交互的状态,此时必要恢复被停息中断的业务,如恢复视频播放或相机预览流等。
开发步调

在创建WindowStage对象后可通过监听’windowStageEvent’事件范例,监听到窗口进入前台、后台、前台可交互、前台不可交互等事件,应用可根据这些上报的事件状态举行相应的业务处理。
  1. import { UIAbility } from '@kit.AbilityKit';
  2. import { window } from '@kit.ArkUI';
  3. export default class EntryAbility extends UIAbility {
  4.   onWindowStageCreate(windowStage: window.WindowStage) {
  5.     try {
  6.       windowStage.on('windowStageEvent', (data) => {
  7.         console.info('Succeeded in enabling the listener for window stage event changes. Data: ' +
  8.           JSON.stringify(data));
  9.         // 根据事件状态类型选择进行相应的处理
  10.         if (data == window.WindowStageEventType.SHOWN) {
  11.           console.info('current window stage event is SHOWN');
  12.           // 应用进入前台,默认为可交互状态
  13.           // ...
  14.         } else if (data == window.WindowStageEventType.HIDDEN) {
  15.           console.info('current window stage event is HIDDEN');
  16.           // 应用进入后台,默认为不可交互状态
  17.           // ...
  18.         } else if (data == window.WindowStageEventType.PAUSED) {
  19.           console.info('current window stage event is PAUSED');
  20.           // 前台应用进入多任务,转为不可交互状态
  21.           // ...
  22.         } else if (data == window.WindowStageEventType.RESUMED) {
  23.           console.info('current window stage event is RESUMED');
  24.           // 进入多任务后又继续返回前台时,恢复可交互状态
  25.           // ...
  26.         }
  27.         // ...
  28.       });
  29.     } catch (exception) {
  30.       console.error('Failed to enable the listener for window stage event changes. Cause:' +
  31.         JSON.stringify(exception));
  32.     }
  33.   }
  34. }
复制代码
鸿蒙全栈开发全新学习指南

有许多小同伴不知道学习哪些鸿蒙开发技术?不知道必要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,终极浪费大量时间。所以要有一份实用的鸿蒙(HarmonyOS NEXT)学习路线与学习文档用来跟着学习是非常有必要的。
针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的焦点知识要点,内容有(ArkTS、ArkUI开发组件、Stage模子、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。
本路线共分为四个阶段:

第一阶段:鸿蒙初中级开发必备技能


第二阶段:鸿蒙南北双向高工技能基础:gitee.com/MNxiaona/733GH


第三阶段:应用开发中高级就业技术


第四阶段:全网首发-工业级南向设备开发就业技术:gitee.com/MNxiaona/733GH


《鸿蒙 (Harmony OS)开发学习手册》(共计892页)

如何快速入门?

1.根本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:gitee.com/MNxiaona/733GH

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台使命(Background Task)管理
11.设备管理
12.设备利用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

鸿蒙开发面试真题(含参考答案):gitee.com/MNxiaona/733GH


鸿蒙入门教学视频:


美团APP实战开发教学:gitee.com/MNxiaona/733GH


写在末了



  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以等待后续文章ing

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表