最近一直在研究鸿蒙上层应用开发,界面设计还算顺利,我一般习惯将整个页面的背景颜色设置为#F0F2F5,查阅了大量文档,并没有发现解决方案,经过一系列的捣鼓,终于有了头绪,下面我来总结一下思路。
需求描述
在日常开发中,很多APP选择使用灰色背景作为底色,白色卡片就能显示得更漂亮;而鸿蒙系统自带上下安全边距,使得我们无法控制上下安全距离内的元素。
解决思路
第一步:在合适的生命周期中开启全屏模式(关闭上下安全距离)
第二步:获取到上下安全距离存储到LocalStorage中,也就是本地持久化存储一下
第三步:自定义安全区域内容,保证显示正常
解决方案
-
编写安全区域管理类,包含 设置全屏模式(沉浸式)、获取顶部安全区域高度、获取底部安全区域高度
-
在需要的生命周期调用实例方法
-
自定义安全区域填充
实施方案
- 编写安全区域管理类,包含 设置全屏模式(沉浸式)、获取顶部安全区域高度、获取底部安全区域高度
我这里存放的位置为src/main/ets/utils
import { window } from '@kit.ArkUI'
class SafeDistanceManager {
private windowStage: window.Window | null = null
// 获取窗口状态
async getWindowStage() {
if(!this.windowStage) {
this.windowStage = await window.getLastWindow(getContext())
}
}
async enableFullScreen() {
await this.getWindowStage()
// 打开全屏模式
this.windowStage?.setWindowLayoutFullScreen(true)
// 状态栏安全距离
const topArea = this.windowStage?.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)
AppStorage.set('TOP_AREA_HEIGHT', px2vp(topArea?.topRect.height))
// 底部安全距离
const bottomArea = this.windowStage?.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
AppStorage.set('BOTTOM_AREA_HEIGHT', px2vp(bottomArea?.topRect.height))
}
}
export const SafeDistance = new SafeDistanceManager()
- 在需要的生命周期调用实例方法
(1)如果想要在所有页面设置全屏模式,在src/main/ets/entryability/EntryAbility.ets
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index',async (err) => {
SafeDistance.enableFullScreen();
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
});
}
在onWindowStageCreate周期中为全局UI实例设置自定义安全距离,一次搞定。
解释一下:
UIAbility实例创建完成之后,在进入Foreground之前,系统会创建一个WindowStage。WindowStage创建完成后会进入onWindowStageCreate()回调,可以在该回调中设置UI加载、设置WindowStage的事件订阅。
在onWindowStageCreate()回调中通过loadContent()方法设置应用要加载的页面,并根据需要调用on('windowStageEvent')方法订阅WindowStage的事件。
(2)如果想要在某个页面设置全屏模式,在src/main/ets/pages/*.ets
import { SafeDistance } from '../utils/SafeDistanceManger';
@Entry
@Component
struct Index {
aboutToAppear(): void {
SafeDistance.enableFullScreen()
}
build() {
}
}
- 编写页面逻辑,自定义安全区域填充
(1)在LocalStorage中获取安全区域高度
@StorageProp('TOP_AREA_HEIGHT') private topAreaHeight: number = 0;
@StorageProp('BOTTOM_AREA_HEIGHT') private bottomAreaHeight: number = 0;
(2)自定义区块占位
Blank().height(this.topAreaHeight).backgroundColor(Color.Black)
完整代码
src/main/ets/utils
import { window } from '@kit.ArkUI'
class SafeDistanceManager {
private windowStage: window.Window | null = null
// 获取窗口状态
async getWindowStage() {
if(!this.windowStage) {
this.windowStage = await window.getLastWindow(getContext())
}
}
async enableFullScreen() {
await this.getWindowStage()
// 打开全屏模式
this.windowStage?.setWindowLayoutFullScreen(true)
// 状态栏安全距离
const topArea = this.windowStage?.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)
AppStorage.set('TOP_AREA_HEIGHT', px2vp(topArea?.topRect.height))
// 底部安全距离
const bottomArea = this.windowStage?.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
AppStorage.set('BOTTOM_AREA_HEIGHT', px2vp(bottomArea?.topRect.height))
}
}
export const SafeDistance = new SafeDistanceManager()
src/main/ets/entryability/EntryAbility.ets
import { window } from '@kit.ArkUI'
class SafeDistanceManager {
private windowStage: window.Window | null = null
// 获取窗口状态
async getWindowStage() {
if(!this.windowStage) {
this.windowStage = await window.getLastWindow(getContext())
}
}
async enableFullScreen() {
await this.getWindowStage()
// 打开全屏模式
this.windowStage?.setWindowLayoutFullScreen(true)
// 状态栏安全距离
const topArea = this.windowStage?.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)
AppStorage.set('TOP_AREA_HEIGHT', px2vp(topArea?.topRect.height))
// 底部安全距离
const bottomArea = this.windowStage?.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
AppStorage.set('BOTTOM_AREA_HEIGHT', px2vp(bottomArea?.topRect.height))
}
}
export const SafeDistance = new SafeDistanceManager()
单页面配置直接借鉴实施方案2.2内容即可
src/main/ets/pages/*.ets
@Entry
@Component
struct Index {
@StorageProp('TOP_AREA_HEIGHT') private topAreaHeight: number = 0;
@StorageProp('BOTTOM_AREA_HEIGHT') private bottomAreaHeight: number = 0;
build() {
Column() {
Blank().height(this.topAreaHeight).backgroundColor(Color.Black)
Row() {
Text('归梦工作室')
.fontSize(20)
.fontWeight(600)
Image($r('app.media.ic_public_view_grid'))
.width(24)
.fillColor(Color.Blue)
}
.width('100%')
.padding(20)
.justifyContent(FlexAlign.SpaceBetween)
Flex() {
Button({ type: ButtonType.Normal, stateEffect: false }) {
Text("sa")
}
.width(100)
.height(100)
.borderRadius(10)
.backgroundColor(Color.White)
}
}
.width('100%')
}
}