鸿蒙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、尾 巴

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21目录1. The Fair Language Model Paradox摘要研究背景问题与挑战如何解决创新点算法模型实验效果重要数据与结论推荐阅读指数&…

stable-zero123模型构建指南

一、介绍 stabilityai出品,能够对有简单背景的物体进行三维视角图片的生成,简单来说也就是通过调整变换观察的视角生成对应视角的图片。 本项目通过comfyui实现。 二、容器构建说明 1. 部署ComfyUI (1)使用命令克隆ComfyUI g…

6,000 个网站上的假 WordPress 插件提示用户安装恶意软件

黑客使用窃取的凭证感染 WordPress 网站,并向其发送虚假插件,通过虚假的浏览器更新提示向最终用户发送恶意软件和信息窃取程序。 该恶意活动基于ClickFix假浏览器更新恶意软件的新变种,自 2024 年 6 月以来已使用假 WordPress 插件感染了超过…

C++ 模板编程:解锁高效编程的神秘密码

快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 目录 💯前言 💯泛型编程 💯函数模板 1.函数模板概念 2.函数模板格式 3.函数模板的原理 4.函数模板的实例化 5.模板参…

社交媒体视频素材平台推荐

在内容创作日益重要的今天,社交媒体视频素材的需求不断增加。适合各种平台的视频素材不仅可以提升内容质量,还能吸引更多观众。以下是一些推荐的社交媒体视频素材平台,帮助你找到适合的资源。 蛙学网 蛙学网 是一个专注于社交媒体视频素材的平…

C# 标准绘图控件 chart 多 Y 值的编程应用

C# 标准绘图控件 chart 多 Y 值的编程应用 1、前言2、声明标准绘图控件 chart 命名空间3、使用绘图控件 chart3.1、在窗体中拖入绘图控件 chart ,拖入绘图控件 chart 最简单实用。3.2、在语句中声明加入,但要将 控件和其组件加入窗体或其它容器很麻烦&am…

2025 - AI人工智能药物设计 - 中药网络药理学和毒理学的研究

中药网络药理学和毒理学的研究 TCMSP:https://old.tcmsp-e.com/tcmsp.php 然后去pubchem选择:输入Molecule Name 然后进行匹配:得到了smiles 再次通过smiles:COC1C(CC(C2C1OC(CC2O)C3CCCCC3)O)O 然后再次输入:http…

尚硅谷-react教程-求和案例-数据共享(下篇)-完成数据共享-笔记

#1024程序员节&#xff5c;征文# public/index.html <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>redux</title></head><body><div id"root"></div></body> </html&…

Vuex的基础

文章目录 vuex概述构建vuex[多组件数据共享]环境创建一个空仓库ps.创建仓库时遇到的错误 核心概念 - state状态核心概念 - mutations辅助函数 - mapMutations 核心概念 - actions辅助函数 - mapActions 核心概念 - getters核心概念 - 模块module&#xff08;进阶语法&#xff0…

Python(pandas库2)

DateFrame的添加 上文中DateFrame的增加中&#xff0c;因版本弃置append函数 如果你想要向 DataFrame 添加一行&#xff0c;建议的方法是首先创建一个新的 DataFrame 来表示这行数据&#xff0c;然后使用 pd.concat() 函数来合并它们。 concat 语法&#xff1a; objs: 要连…

基于协同过滤算法的个性化课程推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

JDBC: Java数据库连接的桥梁

什么是JDBC&#xff1f; Java数据库连接&#xff08;Java Database Connectivity&#xff0c;简称JDBC&#xff09;是Java提供的一种API&#xff0c;允许Java应用程序与各种数据库进行交互。JDBC提供了一组标准的接口&#xff0c;开发者可以利用这些接口执行SQL语句、处理结果集…

「C/C++」C++ STL容器库 之 std::multiset 键的集合容器

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

腾讯云跨AZ部署FortigateHA备忘录

随时保存配置 config system globalset admintimeout 480set alias "FortiGate-VM64-KVM"set gui-auto-upgrade-setup-warning disableset hostname "FG-Slave"set revision-backup-on-logout enableset revision-image-auto-backup enableset timezone &…

【 thinkphp8 】00006 启动 内、外置服务器

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【 t…

Java学习Day53:铲除紫云山金丹原料厂厂长(手机快速登录、权限控制)

1.手机快速登录 手机快速登录功能&#xff0c;就是通过短信验证码的方式进行登录。这种方式相对于用户名密码登录方式&#xff0c;用户不需要记忆自己的密码&#xff0c;只需要通过输入手机号并获取验证码就可以完成登录&#xff0c;是目前比较流行的登录方式。 前端页面&…

centos7.x安装openCV 4.6.0版本

## 从源代码编译安装 1.更新系统 sudo yum update -y 2.安装依赖项 sudo yum groupinstall "Development Tools" sudo yum install cmake gcc-c git libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel openexr-devel gstreamer1-plugins-base-devel…

iTerm2 保持SSH远程连接

1、保持SSH远程连接的稳定&#xff0c;防止因闲置时间过长而断开连接 When idle, send ASCII code 35 every 60 seconds每60秒 输入# 2、客户端设置保持活动 设置客户端每隔60秒发送一次保活信号&#xff0c;总共尝试3次。 vim ~/.ssh/configHost *ServerAliveInterval 60…

uniapp 底部导航栏tabBar设置后不显示的问题——已解决

uniapp 底部导航栏tabBar设置后不显示的问题——已解决 网上找了一堆解决办法&#xff0c;挨个对着试吧 解决办法一&#xff1a;tabBar里的list第一项和page中的第一项要相同&#xff0c;确实就能显示了。但是问题来了&#xff0c;page中的第一项是入口页&#xff0c;那就意味…

鲸鱼优化算法(Whale Optimization Algorithm, WOA)原理与MATLAB例程

鲸鱼优化算法&#xff08;Whale Optimization Algorithm, WOA&#xff09;是一种基于鲸鱼捕食行为的智能优化算法。它模拟了座头鲸在狩猎时的“气泡网”捕食策略。 文章目录 1.适应度函数2. 更新公式2.1 突袭行为2.2 螺旋更新3.线性递减参数4. 边界处理 MATLAB 实现示例代码说明…