HarmonyOS鸿蒙开发 - 解决上下两栏白边 - 沉浸式效果
鸿蒙应用开发从入门到入行
预览器上下两栏白边
自从HarmonyOS升级到release版后,很多同学会问猫林老师:为什么他的预览器上下有白边,为什么明明根容器写了宽高百分百但没铺满。如下图
白边原因
其实上面的白边,称之为状态栏。上面会放手机wifi信号、电池电量等信息。一般情况下我们不需要把应用中具有交互效果的界面延伸到上面去,免得影响操作。
同样,下面的白边称之为导航栏,也即切换手机内应用的地方。会有一个小横条方便你切换不同应用以及回到桌面。
如下图所示
而HarmonyOS升级到release版本后,特意在预览器里把这上下两栏给你留白空出来,就是为了方便让开发者知道,自己的界面并没占用这两个区域,所以一般情况下,如果你的应用整体背景颜色就是白色的,其实是无需处理的。
沉浸式效果介绍
根据上面说的白边情况,如果你的app背景色正好也是白色,那么可以和上下白边融为一体,显得不那么突兀。但如果你的app是别的颜色,那么可能会有明显的突兀感。
举个例子:大家经常用的美团。我们看看它目前的情况,以及假设有白边的情况
这是美团正常情况,会看到顶部是黄色,状态栏也变为黄色,视觉效果上浑然一体
以下假设状态栏白色
可以看到视觉效果上会比较突兀
通过对比我们发现,确实在实际app开发过程中,状态栏上可以不放任何界面元素,但是需要将状态栏的颜色定义的与app背景色保持一致,才会视觉上显得更好看,更融为一体。像这样的效果,我们称之为沉浸式效果
通过上面的描述我们已经发现沉浸式效果能提供比较好的视觉效果,但如何实现呢?
有三种方案都可以实现:
- 通过设置Window背景色来实现
- 通过调用窗口强制全屏布局接口setWindowLayoutFullScreen() + padding避让实现 (麻烦)
- 直接使用扩展到避让区功能
通过设置Window背景色实现沉浸式
设置窗体背景色实现
先看不设置的情况下,我们写的一个宽高百分百,且背景颜色为红色的界面,如下图,可以看到状态栏和整体背景色不一致,有明显突兀感
此时,我们可以设置窗体全局背景色也为红色实现视觉沉浸,来到
EntryAbility.ets,找到onWindowStageCreate生命周期函数,在windowStage.loadContent回调里设置如下代码即可windowStage.getMainWindowSync().setWindowBackgroundColor('#ff0000')注意:这里只能给16进制颜色,且必须满6位
效果如下
- 此时浑然一体
这种方法虽然简单,但有缺点:
预览器依然会有白边,只有模拟器或真机运行才能看到效果
它写死了颜色,每个App里不管是哪个页面都是此颜色,假如你App里多个页面的主题颜色不一样,会导致非常突兀,如下图
使用setWindowLayoutFullScreen实现沉浸式
这是Window提供的一个方法,可以设置让App整屏(即覆盖状态栏与导航栏)实现整块屏幕都可以布局,但是大部分使用时必须配合避让偏移,否则会有问题。至于什么问题呢,我们往下看。
首先来到
EntryAbility.ets,继续找到onWindowStageCreate生命周期函数,在windowStage.loadContent回调里设置如下代码即可windowStage.getMainWindow().then(w => {
// 设置占用全屏
w.setWindowLayoutFullScreen(true)
})这样虽然实现了沉浸式效果,但也存在了问题,例如,我们第一页中本来有Button,但是此时Button位置跑到原来的状态栏去了,如下图
这样的话,会导致原本不该布局的区域也会存在我们的布局元素。第一巨丑,第二用户也点击不了。
因此,我们使用这个方法实现沉浸式时,一般还要做让页面根容器padding避让。也即让我们布局的组件,通过padding的方式挪动他们位置,避让原本的状态栏和导航栏。
例:
Column() {
Button('去下一页')
.onClick(() => {
router.pushUrl({
url: 'pages/Second'
})
})
}
.width('100%')
.height('100%')
.backgroundColor(Color.Red)
.padding({ top: 50, bottom: 50 })此时,我们发现写的按钮确实不会被刘海屏挡住了。但是细心的同学发现了,我们这里写死的50vp。不合理,有可能给少了,也有可能给多了。毕竟不同设备的状态栏可能不一样。所以如果我们使用这种方案还需要获取屏幕的状态栏与导航栏的高度。然后把高度存到本地存储里,方便所有页面都可以使用并设置padding
具体步骤:继续来到
onWindowStageCreate,填写如下代码onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); windowStage.loadContent('pages/Index', (err) => {
// windowStage.getMainWindowSync().setWindowBackgroundColor('#ff0000')
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
} // 以下是设置沉浸式,以及获取设备导航条、状态栏高度的代码
windowStage.getMainWindow().then(w => {
// 设置沉浸式
w.setWindowLayoutFullScreen(true)
// 获取设备区域参数
let avoidArea = w.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)
let bottomRectHeight = avoidArea.bottomRect.height; // 获取到导航条区域的高度
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight); // 存到本地存储
let topRectHeight = avoidArea.topRect.height; // 获取状态栏区域高度
AppStorage.setOrCreate('topRectHeight', topRectHeight); // 存到本地存储 // 当区域发生改变(例如竖屏变横屏),重新获取一次再保存
w.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);
}
});
})
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
});
}好了,上面每句代码都有注释,可以根据注释去理解。当然咯,我知道你们没兴趣看代码,所以需要用可以直接复制,反正这个代码是固定的
然后来到页面里,先取出本地存储的值,且用@StorageProp装饰器,设置状态自动更新。
@StorageProp('bottomRectHeight')
bottomRectHeight: number = 0;
@StorageProp('topRectHeight')
topRectHeight: number = 0;然后把这两个变量,设置给根容器的padding即可
@StorageProp('bottomRectHeight')
bottomRectHeight: number = 0;
@StorageProp('topRectHeight')
topRectHeight: number = 0; build() {
Column() {
Button('去下一页')
.onClick(() => {
router.pushUrl({
url: 'pages/Second'
})
})
}
.width('100%')
.height('100%')
.backgroundColor(Color.Red)
.padding({ top: px2vp(this.topRectHeight), bottom: px2vp(this.bottomRectHeight) })同样的,其他页面也如此设置即可
这样,我们通过一系列操作。以及一段代码实现了沉浸式效果。但大家也发现明显的缺点
预览器依然没效果,需要真机或模拟器查看
代码过多。好多没耐心的同学看到这,可能都已经烦躁的想打人了
这样子会让所有页面都被迫使用沉浸式,如果哪个页面不需要沉浸式,还需要再此页面的about里禁用
aboutToAppear(): void {
window.getLastWindow(getContext())
.then(win => {
win.setWindowLayoutFullScreen(false)
})
}
因此,我们还有最为简单的一种方式,请往下继续看
使用expandSafeArea设置沉浸式(推荐)
expandSafeArea是一个按需方式的沉浸式方案,它能完美起到哪个页面需要沉浸式,就在哪个页面使用即可,绝对不会让整个App每个页面都强制沉浸式。而且使用起来非常简单,只需要在需要沉浸式的页面的根容器里设置即可,例
Column() {
Button('去下一页')
.onClick(() => {
router.pushUrl({
url: 'pages/Second'
})
})
}
.width('100%')
.height('100%')
.backgroundColor(Color.Red)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])解释:参数1固定,参数2是设置需要沉浸式的区域,
SafeAreaEdge.TOP代表上面状态栏沉浸式,SafeAreaEdge.BOTTOM代表下面导航栏沉浸式,此时效果如下- 没错,此时不需要启动模拟器,预览器也可以直接看到效果!
当然,你也可以只设置让顶部沉浸式,则第二个参数只要写一个TOP即可,如下代码
Column() {
// 生略里面代码
}
.width('100%')
.height('100%')
.backgroundColor(Color.Red)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])效果如下
扩展思考:setWindowLayoutFullScreen是否很鸡肋?
同学们到目前为止,发现实现沉浸式我们用了三种方案。其中第一种设置Window背景色可以无视掉,这种方法我们基本不会用。而第二种方法能实现,但又比较麻烦,第三种是最容易也最推荐的方式。
但此时请我们思考下:setWindowLayoutFullScreen是否真的一点应用场景都没有?
要想回答这个问题,我们可以从setWindowLayoutFullScreen的特点入手,大家还记得吗?setWindowLayoutFullScreen最大的特点是让app所有页面都强制全屏(沉浸式),那么大家仔细想想,有没有哪种App是需要任意页面都强制全屏的呢?
- 没错,答案是游戏!如下图
像这样的,如果以后是游戏类App,我们必然需要使用setWindowLayoutFullScreen一次性设置所有页面全屏
因此,这个方法,大家也需要有点印象哦!万一哪天要用到呢?
请思考:还有没有除了游戏以外也可能要用到setWindowLayoutFullScreen的场景呢?把你的想法可以打在评论区
HarmonyOS鸿蒙开发 - 解决上下两栏白边 - 沉浸式效果的更多相关文章
- Android 开发学习进程0.11 pageview relativelayout 沉浸式标题栏
fragment与pageView fragment fragment不可以侧滑切换相关界面,但多数代码位于fragment中,易于维护,同时不会受到多个手势滑动的影响 pageView pageVi ...
- 鸿蒙HarmonyOS应用开发落地实践,Harmony Go 技术沙龙落地北京
12月26日,华为消费者BG软件部开源中心与51CTO Harmony OS技术社区携手,共同主办了主题为"Harmony OS 应用开发落地实践"的 Harmony Go 技术沙 ...
- 【资源下载】Linux下的Hi3861一站式鸿蒙开发烧录(附工具)
下载附件 2021春节前夕,华为发布了 HUAWEI DevEco Device Tool 2.0 Beta1,整体提供了异常强大的功能.得知消息后,我在第一时间带着无比兴奋的心情下载尝鲜,但结果却是 ...
- 它来了,它来了,HarmonyOS应用开发在线体验来了
接下来是我们的两分钟科普,一分钟玩转HarmonyOS应用开发在线体验,一分钟简单了解"一次开发.多设备部署"的原理.萌新的开发者也能第一时间掌握,往下看吧~ 一分钟玩转Harmo ...
- css布局 - 工作中常见的两栏布局案例及分析
突然想到要整理这么一篇平时工作中相当常见但是我们又很忽视的布局的多种处理方法.临时就在我经常浏览的网站上抓的相对应的截图.(以后看到其他类型的我再补充) 既然截了图,咱们就直接看人家使用的布局方式,毕 ...
- 鸿蒙开发板外设控制 之 实现按键“按下事件”和“释放事件”的通用框架(V0.0.1)
在帖子 <鸿蒙开发板外设控制>直播图文版(2020.10.28) 中我们提到过:"开发板上的按键也可以看作一种 GPIO 外设." 因此,要捕捉按键的状态(按下或释放) ...
- 用鸿蒙开发AI应用(七)触摸屏控制LED
[小年答谢,新春送礼]免费抽取1000元京东卡+更多新春好礼~查看详情>>> 目录:前言背景知识编译用户程序框架子系统基于AbilityKit开发的Ability总结 前言上一篇,我 ...
- 用鸿蒙开发AI应用(八)JS框架访问内核层
目录:前言JS应用开发框架原理内置模块实现ace模块开发界面程序 前言上回说到,用C++来写UI界面的开发效率不如JS+HTML来的高,但设备开发又免不了要通过内核态来操作硬件,这里我们就要先打通从J ...
- CozyRSS开发记录3-标题栏再加强
CozyRSS开发记录3-标题栏再加强 1.更精炼的标题栏 接下来,我们把窗口的边框和默认的标题栏给去掉,让Cozy看起来更像一个平板应用. 在主窗口的属性里,修改下列两个属性: 效果一目了然: 2. ...
- CSS 实现:两栏布局(等宽布局)
☊[实现要求]:两栏等宽布局 <div class="demo3"> <div class="col-1"></div> & ...
随机推荐
- Nuxt Kit API :路径解析工具
title: Nuxt Kit API :路径解析工具 date: 2024/9/22 updated: 2024/9/22 author: cmdragon excerpt: 摘要:本文介绍了Nux ...
- ptmalloc、tcmalloc与jemalloc对比分析
背景介绍 在开发微信看一看期间,为了进行耗时优化,基础库这层按照惯例使用tcmalloc替代glibc标配的ptmalloc做优化,CPU消耗和耗时确实有所降低.但在晚上高峰时期,在CPU刚刚超过50 ...
- AMBA总线架构简介
于是乎,我们想到了总线,用一个统一的接口协议,设计出一个符合要求的总线,然后将ARM核和各种外设模块挂载在总线上,这样,命令和数据似乎便可以在CPU和外设之间自由穿梭. 1 AMBA总线 AMBA,英 ...
- Xcode 12 引用缺失包:libstdc++.tbd libstdc++.6.tbd libstdc++.6.0.9.tbd引发的一系列问题解析
升级到xcode12后会有libstdc++.tbd libstdc++.6.tbd libstdc++.6.0.9.tbd 等库缺失的情况,并引发一些列的 Undefined symbols for ...
- 我在大厂做 CR——为什么建议使用枚举来替换布尔值
使用枚举替换布尔值主要基于以下几个原因 ● 可读性 ● 可拓展性 ● 安全防控 可读性 我们会定义 boolean 类型(true 或 false)作为方法参数,虽然比较简洁,但有时候参数的含义往往不 ...
- 用 KubeKey 快速离线部署 K8s 与 KubeSphere
作者:尹珉,KubeSphere Ambassador,KubeSphere 社区用户委员会杭州站站长 一.KubeKey 介绍 KubeKey(以下简称 KK) 是一个用于部署 Kubernetes ...
- mysql的执行流程
本篇章为构建mysql在执行过程中简单的业务流程,为后续的代码优化和面试构建基础. 1.首先一条sql在执行时sql会通过网络传送给mysql 2.在Mysql收到sql语句后会先在分析器中先判断一下 ...
- idea高效实用快捷键【待补充】
1.快捷键 ctrl+alt+L代码格式化 2.快捷键 ctrl+h查看hierarchy,只能查看向上向下继承关系,而不能看实现了哪些接口. 3,选中右键--Diagram可以查看实现了哪些接口 4 ...
- 鱼香ROS一键安装软件
一行代码-解决人生烦恼 推荐语:一行代码搭建机器人开发环境(ROS/ROS2/ROSDEP) 开源地址:https://github.com/fishros/install 一键安装指令 wget h ...
- LookupViT:类似SE的token压缩方案,加速还能丰富特征 | ECCV'24
视觉变换器(ViT)已成为众多工业级视觉解决方案的事实标准选择.但由于每一层都计算自注意力,这导致其推理成本对许多场景而言是不可接受的,因为自注意力在标记数量上具有平方的计算复杂度.另一方面,图像中的 ...