鸿蒙UI开发——基于全屏方案实现沉浸式界面

1、概 述

典型应用全屏窗口UI元素包括状态栏、应用界面和底部导航条。

其中状态栏和导航条,通常在沉浸式布局下称为避让区,避让区之外的区域称为安全区

开发应用沉浸式效果主要指:通过调整状态栏、应用界面和导航条的显示效果来减少状态栏导航条等系统界面的突兀感,保证应用的整体观感。

作为对比(未沉浸式左图、沉浸式的右图),示意如下:

图片

大部分情况下,为了保证应用界面的一致性,我们都需要做沉浸式界面适配。

实现沉浸式效果的方式有两种:

  1. 窗口全屏布局:调整布局系统为全屏布局,界面元素延伸到状态栏和导航条区域(当不隐藏避让区时,可通过接口查询状态栏和导航条区域进行可交互元素避让处理,还可以设置状态栏或导航条的颜色等属性与界面元素匹配。当隐藏避让区时,通过对应接口设置全屏布局)

  2. 组件安全区:  布局系统保持安全区内布局,然后通过接口延伸绘制内容(如背景色,背景图)到状态栏和导航条区域(本方案中界面元素仅做绘制延伸,无法单独布局到状态栏和导航条区域,如果需要单独布局UI元素到状态栏和导航条区域的场景最好还是使用窗口全屏布局方案处理)。

2、窗口全屏布局

全屏布局方式有两个场景:1)不隐藏避让区、2)隐藏避让区。

    • 针对普通的应用场景,我们一般不会隐藏避让区(显示状态和导航条);

    • 针对游戏场景,我们一般会隐藏避让区(隐藏状态栏和导航条);

2.1、不隐藏避让区

不隐藏避让区一般常见于常规的应用界面中,他保留了界面中的导航栏和顶部的状态栏。开发方式大致分两步,介绍如下:

👉🏻 step 1

我们可以通过调用窗口强制全屏布局接口setWindowLayoutFullScreen()实现界面元素延伸到状态栏和导航条;

👉🏻 step 2 

再通过接口getWindowAvoidArea()和on('avoidAreaChange')获取并动态监听避让区域的变更信息,页面布局根据避让区域信息进行动态调整(也可以设置状态栏或导航条的颜色等属性与界面元素进行匹配)。

开发实例如下:

a. 调用 setWindowLayoutFullScreen() 接口设置窗口全屏

// EntryAbility.etsimport { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';import { window } from '@kit.ArkUI';import { BusinessError } from '@kit.BasicServicesKit';export default class EntryAbility extends UIAbility {  // ...  onWindowStageCreate(windowStage: window.WindowStage): void {    windowStage.loadContent('pages/Index', (err, data) => {      if (err.code) {        return;      }      let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口      // 1. 设置窗口全屏      let isLayoutFullScreen = true;      windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => {        console.info('Succeeded in setting the window layout to full-screen mode.');      }).catch((err: BusinessError) => {        console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));      });    });  }}

b. 使用  getWindowAvoidArea()  接口获取当前布局遮挡区域(例如: 状态栏、导航条)

// EntryAbility.etsimport { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';import { window } from '@kit.ArkUI';export default class EntryAbility extends UIAbility {  // ...  onWindowStageCreate(windowStage: window.WindowStage): void {    windowStage.loadContent('pages/Index', (err, data) => {      if (err.code) {        return;      }      let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口      // 1. 设置窗口全屏      // ...      // 2. 获取布局避让遮挡的区域      let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 以导航条避让为例      let avoidArea = windowClass.getWindowAvoidArea(type);      let bottomRectHeight = avoidArea.bottomRect.height; // 获取到导航条区域的高度      AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);      type = window.AvoidAreaType.TYPE_SYSTEM; // 以状态栏避让为例      avoidArea = windowClass.getWindowAvoidArea(type);      let topRectHeight = avoidArea.topRect.height; // 获取状态栏区域高度      AppStorage.setOrCreate('topRectHeight', topRectHeight);    });  }}

c. 注册监听函数,动态获取避让区域的实时数据

// EntryAbility.etsimport { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';import { window } from '@kit.ArkUI';export default class EntryAbility extends UIAbility {  // ...  onWindowStageCreate(windowStage: window.WindowStage): void {    windowStage.loadContent('pages/Index', (err, data) => {      if (err.code) {        return;      }      let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口      // 1. 设置窗口全屏      // ...      // 2. 获取当前布局避让遮挡的区域      // ...      // 3. 注册监听函数,动态获取避让区域数据      windowClass.on('avoidAreaChange', (data) => {        if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {          let topRectHeight = data.area.topRect.height;          AppStorage.setOrCreate('topRectHeight', topRectHeight);        } else if (data.type == window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {          let bottomRectHeight = data.area.bottomRect.height;          AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);        }      });    });  }}

d. 布局中的UI元素需要避让状态栏和导航条(否则可能产生UI元素重叠等情况)

对控件顶部设置padding(具体数值与状态栏高度一致),实现对状态栏的避让;对底部设置padding(具体数值与底部导航条区域高度一致),实现对底部导航条的避让(如果去掉顶部和底部的padding设置,即不避让状态栏和导航条,UI元素就会发生重叠)@Entry

@Componentstruct Index {  @StorageProp('bottomRectHeight')  bottomRectHeight: number = 0;  @StorageProp('topRectHeight')  topRectHeight: number = 0;  build() {    Row() {      Column() {        Row() {          Text('DEMO-ROW1').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('DEMO-ROW2').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('DEMO-ROW3').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('DEMO-ROW4').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('DEMO-ROW5').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('DEMO-ROW6').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)      }      .width('100%')      .height('100%')      .alignItems(HorizontalAlign.Center)      .justifyContent(FlexAlign.SpaceBetween)      .backgroundColor('#008000')      // top数值与状态栏区域高度保持一致;bottom数值与导航条区域高度保持一致      .padding({ top: this.topRectHeight, bottom: this.bottomRectHeight })    }  }}

布局避让状态栏和导航条效果如下(顶部状态栏和底部导航栏没有于DEMO-ROWx重叠):

图片

布局未避让状态栏和导航条(DEMO-ROWx与顶部状态栏和底部导航栏元素重叠):

图片

e. 根据实际的UI界面显示或相关UI元素背景颜色等,还可以按需设置状态栏的文字颜色、背景色或设置导航条的显示或隐藏,以使UI界面效果呈现和谐(状态栏默认是透明的,透传的是应用界面的背景色)

【此例中UI颜色比较简单,没有对状态栏文字颜色、背景色进行单独设置】

如果需要设置,示例如下:

// EntryAbility.etsimport { UIAbility } from '@kit.AbilityKit';import { BusinessError } from '@kit.BasicServicesKit';export default class EntryAbility extends UIAbility {  // ...  onWindowStageCreate(windowStage: window.WindowStage): void {    console.info('onWindowStageCreate');    let windowClass: window.Window | undefined = undefined;    windowStage.getMainWindow((err: BusinessError, data) => {      const errCode: number = err.code;      if (errCode) {        console.error(`Failed to obtain the main window. Cause code: ${err.code}, message: ${err.message}`);        return;      }      windowClass = data;      let systemBarProperties: window.SystemBarProperties = {        statusBarColor: '#ff00ff', // 状态栏背景颜色        navigationBarColor: '#00ff00', // 导航栏背景颜色        statusBarContentColor: '#ffffff', // 状态栏文字颜色        navigationBarContentColor: '#00ffff' // 导航栏文字颜色      };      try {      // 设置自定义d的状态栏和导航栏的样式        let promise = windowClass.setWindowSystemBarProperties(systemBarProperties);        promise.then(() => {          console.info('Succeeded in setting the system bar properties.');        }).catch((err: BusinessError) => {          console.error(`Failed to set the system bar properties. Cause code: ${err.code}, message: ${err.message}`);        });      } catch (exception) {        console.error(`Failed to set the system bar properties. Cause code: ${exception.code}, message: ${exception.message}`);      }    });  }}

2.2、隐藏避让区

隐藏避让区一般常见于游戏、视频全屏播放类型的场景,顶部状态栏和底部的导航栏都常驻显示在界面中(可以通过从底部上滑唤出导航条)。例如:

图片

开发实例如下:

a. 调用 setWindowLayoutFullScreen() 接口设置窗口全屏。

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';import { window } from '@kit.ArkUI';import { BusinessError } from '@kit.BasicServicesKit';export default class EntryAbility extends UIAbility {  // ...  onWindowStageCreate(windowStage: window.WindowStage): void {    windowStage.loadContent('pages/Index', (err, data) => {      if (err.code) {        return;      }      let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口      // 1. 设置窗口全屏      let isLayoutFullScreen = true;      windowClass.setWindowLayoutFullScreen(isLayoutFullScreen)        .then(() => {          console.info('Succeeded in setting the window layout to full-screen mode.');        })        .catch((err: BusinessError) => {          console.error(`Failed to set the window layout to full-screen mode. Code is ${err.code}, message is ${err.message}`);        });    });  }}

b. 调用 setSpecificSystemBarEnabled() 接口设置状态栏和导航条的具体显示/隐藏状态。​​​​​​

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';import { window } from '@kit.ArkUI';import { BusinessError } from '@kit.BasicServicesKit';export default class EntryAbility extends UIAbility {  // ...  onWindowStageCreate(windowStage: window.WindowStage): void {    windowStage.loadContent('pages/Index', (err, data) => {      if (err.code) {        return;      }      let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口      // 1. 设置窗口全屏      // ...      // 2. 设置状态栏和导航条隐藏      windowClass.setSpecificSystemBarEnabled('status', false)        .then(() => {          console.info('Succeeded in setting the status bar to be invisible.');        })        .catch((err: BusinessError) => {          console.error(`Failed to set the status bar to be invisible. Code is ${err.code}, message is ${err.message}`);        });    });  }}

c. 在界面中无需进行导航条避让操作(导航条不显示在界面中,没必要做避让操作)

@Entry()@Componentstruct Index {  build() {    Row() {      Column() {        Row() {          Text('ROW1').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('ROW2').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('ROW3').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('ROW4').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('ROW5').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)        Row() {          Text('ROW6').fontSize(40)        }.backgroundColor(Color.Orange).padding(20)      }      .width('100%')      .height('100%')      .alignItems(HorizontalAlign.Center)      .justifyContent(FlexAlign.SpaceBetween)      .backgroundColor('#008000')    }  }}

3、尾 巴

由于篇幅原因,本文暂只介绍基于全屏方案的沉浸式界面实现案例,除了基于全屏的方案,我们还可以使用基于组件安全区的方案实现沉浸式界面,后续再继续讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58563.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

规划误差降低27%,碰撞率降低33%Senna: 大规模视觉-语言模型与端到端自动驾驶相结合

Abstract 端到端自动驾驶在大规模数据中展示了强大的规划能力,但在复杂、罕见的场景中仍然因常识有限而表现不佳。相比之下,大型视觉语言模型(LVLMs)在场景理解和推理方面表现出色。前进的方向在于融合两者的优势。以往利用LVLMs…

openpnp - 手工修改配置文件(元件高度,size,吸嘴)

文章目录 openpnp - 手工修改配置文件(元件高度,size,吸嘴)概述笔记parts.xmlpackages.xml 手工将已经存在的NT1,NT2拷贝出来改名备注END openpnp - 手工修改配置文件(元件高度,size,吸嘴) 概述 载入新板子贴片准备时,除了引入Named CSV文件,还要在ope…

硬件电子器件学习笔记

系列文章目录 文章目录 系列文章目录电阻碳质电阻器线绕电阻 变压器自耦变压器隔离变压器 电阻 碳质电阻器 CCR: 优点:体积大,吸收脉冲电流、防浪涌。缺点:温度系数、稳定性差、吸水后也会变化、随着使用会变化。 医用除颤仪可…

推荐一款射频与微波电路设计软件:Keysight Genesys

Keysight PathWave RF Synthesis Genesys是一款专为射频 (RF) 和微波电路设计与仿真而开发的软件解决方案,属于 Keysight Technologies 的 PathWave 软件平台。此平台为无线通信系统的设计、仿真和验证提供了全面的工具支持。Genesys 在电路设计方面具备高度专业性&…

创新业态下金融头部机构在 FICC 平台建设上的思考与实践

近年来,FICC 投资交易呈现活跃多元态势,创新转型稳步推进。FICC 平台电子化方兴未艾,是机构提升服务效率和质量的一大着力点。因此,在 FICC 平台建设上,许多机构都进行了深入研究,积累了丰富的实践经验。 …

(五)Web前端开发进阶2——AJAX

目录 1.Ajax概述 2.Axios库 3.认识URL 4.Axios常用请求方法 5.HTTP协议——请求报文/响应报文 6.HMLHttpRequest对象 7.前后端分离开发(接口文档) 8.Element组件库 1.Ajax概述 AJAX 是异步的 JavaScript和XML(Asynchronous JavaScript And XML)。…

linux文件的权限

前言 在linux操作系统中,账户分为两类,一类是普通用户,一类是超级用户,普通用户在许多方面受权限约束,而超级用户几乎不受约束。 root账户和普通账户的切换 有三种方式能够切换账号 su su 直接使用,会弹…

【CSS3】css开篇基础(5)

1.❤️❤️前言~🥳🎉🎉🎉 Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的…

net framework 3.5组件更新失败错误代码0x80072f8f怎样解决

浏览器地址栏输入www.dnz9.com远程解决netframework问题 当遇到.NET Framework 3.5 组件更新失败,错误代码为 0x80072f8f 时,可以尝试以下几种解决方法: 一、检查网络连接和时间设置 网络连接 错误代码 0x80072f8f 通常与网络相关问题有关。首…

STM32F103C8T6学习笔记2--LED流水灯与蜂鸣器

1、简要说明与电路图 LED灯与蜂鸣器都是GPIO的输出操作,给高低电平实现。GPIO操作也是后续操作的基础,没有什么难度,记不住寄存器没关系,只要把流程理清楚就可以了。 端口配置成推挽输出模式,高低电平均有驱动能力。 …

计算机网络网络层笔记

互联网提供的两种服务 1.虚电路服务 2.数据报服务 需要记住的是现在只用第二种也就是数据报服务 网际协议IP 物理层的中断系统:转发器(hub) 链路层的中断系统:交换机 网络层的中断系统:路由器 网络层以上:网关 如上图所示,网关是用来访问其他的网段的一个接口,网关的地…

大屏可视化:舞动数据与美观的“设计秘籍”

大屏可视化鉴赏:踏入软件系统产品设计之旅,让我们一同鉴赏那些闪耀在智慧农业、智慧园区、智慧社区及智慧港口等领域的大屏可视化杰作。每一帧画面,都是科技与创新的完美融合,数据跃然屏上,智慧触手可及。 >> 数…

持续基础怎么搞?Jenkins+Docker+Git实战

在如今的互联网时代,随着软件开发复杂度的不断提高,软件开发和发布管理也越来越重要。目前已经形成一套标准的流程,最重要的组成部分就是持续集成(Continuous Integration,CI)及持续部署、交付(…

EDA --软件开发之路

之前一直在一家做数据处理的公司,从事c开发,公司业务稳定,项目有忙有闲,时而看下c,数据库,linux相关书籍,后面跳槽到了家eda公司,开始了一段eda开发之路。 eda 是 electric design …

「Mac畅玩鸿蒙与硬件10」鸿蒙开发环境配置篇10 - 项目实战:计数器应用

本篇将通过一个简单的计数器应用,带你体验鸿蒙开发环境的实际操作流程。本项目主要练习组件的使用、事件响应和状态管理,帮助开发者熟悉基本的应用构建流程。 关键词 计数器应用组件操作事件响应状态管理HarmonyOS 应用开发一、创建计数器项目 1.1 在 DevEco Studio 中新建项…

window快捷键:window + v 打开剪切板历史记录 / 非常实用

一、剪切板历史记录功能介绍 1.1、window v 打开剪切板历史记录 / 文字、图片都可记录 1.2、window v 最近使用 1.3、window v 表情符号 1.4、window v GIF 1.5、window v 颜文字 1.6、window v 符号 二、欢迎交流指正

寻找专业在线微信投票和点赞服务团队攻略

在当今的社交网络时代,微信投票和点赞活动日益频繁,无论是企业评选、才艺比赛还是个人荣誉的角逐,都可能需要一定的投票和点赞支持。然而,要找到领先、高效、专业的在线微信投票和点赞服务团队并非易事。以下是一些关键步骤和注意…

115页PPT华为管理变革:制度创新与文化塑造的核心实践

集成供应链(ISC)体系 集成供应链(ISC)体系是英文Integrated Supply Chain的缩写,是一种先进的管理思想,它指的是由相互间提供原材料、零部件、产品和服务的供应商、合作商、制造商、分销商、零售商、顾客等…

Games101 05~06 - Raterization 光栅化

1.Viewport Transformation视口变换: 1.1Canonical Cube 之前我们通过MVP矩阵把物体坐标变换到正方体中(每个顶点的x,y,z坐标都应该在-1.0到1.0之间)也被称为裁剪空间clip space,接下来我们需要将该空间映…

为Meta Spark准备3D模型

有许多工具可以帮助你为 Meta Spark Studio 创建 3D 对象,包括 Cinema4D、Blender 和 3ds Max。你还可以使用 Meta Spark Toolkit 优化 Blender 对象。 在本指南中,我们将介绍正确的设置,以便你可以成功地为 Meta Spark Studio 准备对象&…