一 概述
鸿蒙移除了三键导航(导航栏)换成了导航条,但是还存在获取导航栏高度、隐藏导航栏和设置导航栏高度以及内容颜色的API,所以封装一个ImmersionBar的util使用 ,如果想看修改状态栏背景颜色的,请在真机下看,模拟器不生效
1.1 方案一: Navigation 以及 NavDestination 伪沉浸式
Navigation现在是鸿蒙推荐的页面以及路由方案,它本身就是一个沉浸式,但是内容会避免 ,API Version 11开始默认支持安全区避让特性,但是定制化比较低,只是Navigation会包括状态栏和导航条(导航栏),比如我们设置Navigation的 backgroundColor(Color.Red),但是如果设置成了真正的沉浸式,那么Navigation的Content内容就会铺满屏幕
1.2 方案二: window.setWindowSystemBarEnable,隐藏状态栏或者导航栏,相当于真正全屏模式
- 隐藏状态栏或者导航栏,window.setWindowSystemBarEnable([])
- 显示状态栏或者导航栏 window.setWindowSystemBarEnable(['navigation', 'status'])
- status :控制着 导航条 和 状态栏
- navigation:控制着导航栏,但是现在鸿蒙没有导航栏。。。
1.3 方案三: setWindowLayoutFullScreen 沉浸式,不是设置全屏
设置主窗口或子窗口的布局是否为沉浸式布局,这个方法 会保留状态栏和导航条(导航栏),感觉跟他的名字不太符合他的名字(如果想实现真正的全屏,请使用 setWindowSystemBarEnable ),api12 之后推荐使用 setImmersiveModeEnabledState
,然后配合着更改状态栏和导航栏背景颜色以及内容颜色,来实现内容
let windowClass = await window.getLastWindow(getContext(this))
windowClass.setWindowLayoutFullScreen(true)
.then(() => {
Logger.info('设置成功')
}).catch((e: BusinessError) => {
Logger.info(e)
})
1.4 方案四: setImmersiveModeEnabledState
使用 setImmersiveModeEnabledState(沉浸式) 配合 setWindowSystemBarProperties(设置状态栏导航栏颜色)
let windowClass = await window.getLastWindow(getContext(this))
windowClass.setImmersiveModeEnabledState(true)
二 封装 ImmersionBar 的工具类
先创建一个Config类
- fullScreen:是否为全屏布局,即隐藏状态栏和导航条(导航栏),如果为 true ,那么相当于其他的无效,其他配置都会被无视
- immersion: 是否是沉浸式
- statusBarColor: 设置状态的背景颜色
- statusBarContentColor: 状态栏栏文字颜色
- navigationBarColor: 设置导航栏背景颜色,但是鸿蒙去掉了导航栏,增加了导航条,(先保留着这个属性吧)
- navigationBarContentColor: 导航栏文字颜色,但是鸿蒙去掉了导航栏,增加了导航条(先保留着这个属性吧)
export interface ImmersionConfig {
// 是否为全屏布局,即隐藏状态栏和导航条(导航栏),
// 如果为 true ,那么相当于其他的无效,其他配置都会被无视
fullScreen?: boolean
// 是否是沉浸式
immersion?: boolean
// 设置状态的背景颜色
statusBarColor?: string
// 状态栏栏文字颜色
statusBarContentColor?: string
// 设置导航栏背景颜色,但是鸿蒙去掉了导航栏,增加了导航条,(先保留着这个属性吧)
navigationBarColor?: string
// 导航栏文字颜色,但是鸿蒙去掉了导航栏,增加了导航条(先保留着这个属性吧)
navigationBarContentColor?: string
}
ImmersionBar 工具类
有一个坑点,大部分一个App就一个window,如果一处设置配置之后,比如沉浸式,全部都是沉浸式,需要在移除这个页面的时候,再还原成以前的配置,所以我们需要记录上一个的配置信息。比如我们A(非沉浸式)->B(沉浸式),我们需要在B的 onPageShow 的里面先拿到上一个的配置,在设置沉浸式,在B的onPageHide时候,再还原回来原来的配置
- with(window?: window.Window),绑定当前的window,如果不调用,默认使用的是
getLastWindow
- getStatusHeight:获取状态栏的高度,单位是vp,全屏下是0
- getNavigationHeight:导航条+导航栏 的高度,单位是vp,时候咱们不关心到底是导航栏还是导航条,我们只想做沉浸式,可以使用此方法,全屏下是0
- getNavigationIndicatorHeight:获取导航条的高度,单位是vp,全屏下是0
- getNavigationBarHeight:获取导航栏的高度,单位是vp,鸿蒙去掉了导航栏,加入了导航条。也暂时放这里,但是还有获取导航栏高度、设置导航栏颜色、设置导航栏是否隐藏的api,估摸着 可能为老版手机升级到鸿蒙做的适配,全屏下是0
- setImmersion 设置沉浸式,如果只想简单的设置沉浸式,可以直接调用这个
- removeImmersion 移除沉浸式
- init(config?: ImmersionConfig),根据 ImmersionConfig 设置是否全屏,是否沉浸式,状态栏和导航栏背景颜色以及字体颜色
- getCurrentConfig(),获取当前的Config
class ImmersionBar {
private window?: window.Window
private config: ImmersionConfig = {}
with(window?: window.Window) {
this.window = window
return this;
}
/**
* 拿到当前的配置信息,还原的时候,直接设置这个就行
* @returns
*/
getCurrentConfig(): ImmersionConfig {
return this.config;
}
/**
* @returns 获取状态栏的高度,单位是vp
*/
async getStatusHeight(): Promise<number> {
await this.checkWindow()
let type = window.AvoidAreaType.TYPE_SYSTEM;
let avoidArea = this.window?.getWindowAvoidArea(type);
return px2vp(avoidArea?.topRect.height)
}
/**
* 鸿蒙去掉了导航栏,加入了导航条。也暂时放这里把,
* 但是还有获取导航栏高度、设置导航栏颜色、设置导航栏是否隐藏的api,估摸着 可能为老版手机升级到鸿蒙做的适配
* @returns 获取导航栏的高度,单位是vp
*/
async getNavigationBarHeight(): Promise<number> {
await this.checkWindow()
let type = window.AvoidAreaType.TYPE_SYSTEM;
let avoidArea = this.window?.getWindowAvoidArea(type);
return px2vp(avoidArea?.bottomRect.height)
}
/**
* 获取导航条的高度
* @returns 获取导航条的高度,单位是vp
*/
async getNavigationIndicatorHeight(): Promise<number> {
await this.checkWindow()
let avoidAreaNavi = this.window?.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
return px2vp(avoidAreaNavi?.bottomRect.height)
}
/**
* 获取 导航条+导航栏 的高度
* @returns 获取 导航条+导航栏 的高度,单位是vp
*/
async getNavigationHeight(): Promise<number> {
await this.checkWindow()
let indicatorHeight = await this.getNavigationIndicatorHeight()
let navigationBar = await this.getNavigationBarHeight()
return indicatorHeight + navigationBar;
}
/**
* 设置沉浸式
*/
async setImmersion(): Promise<void> {
await this.checkWindow()
this.config.immersion = true
this.window?.setImmersiveModeEnabledState(true)
}
/**
* 移除沉浸式
*/
async removeImmersion(): Promise<void> {
await this.checkWindow()
this.config.immersion = false
this.window?.setImmersiveModeEnabledState(false)
}
async init(config?: ImmersionConfig): Promise<void> {
await this.checkWindow()
if (config) {
// 设置当前的config
this.config = this.config
if (config.fullScreen != undefined) {
let names: Array<'status' | 'navigation'> = [];
if (!config.fullScreen) {
names.push('status')
names.push('navigation')
}
this.window?.setWindowSystemBarEnable(names)
}
// 是否沉浸式
if (config.immersion != undefined) {
this.window?.setImmersiveModeEnabledState(config.immersion)
}
// 状态栏颜色
await this.window?.setWindowSystemBarProperties(config as window.SystemBarProperties)
}
}
private async checkWindow(): Promise<void> {
if (!this.window) {
this.window = await window.getLastWindow(getContext(this))
}
}
}
export interface ImmersionConfig {
// 是否为全屏布局,即隐藏状态栏和导航条(导航栏),
// 如果为 true ,那么相当于其他的无效,其他配置都会被无视
fullScreen?: boolean
// 是否是沉浸式
immersion?: boolean
// 设置状态的背景颜色
statusBarColor?: string
// 状态栏栏文字颜色
statusBarContentColor?: string
// 设置导航栏背景颜色,但是鸿蒙去掉了导航栏,增加了导航条,(先保留着这个属性吧)
navigationBarColor?: string
// 导航栏文字颜色,但是鸿蒙去掉了导航栏,增加了导航条(先保留着这个属性吧)
navigationBarContentColor?: string
}
export default new ImmersionBar()
使用的demo
Column({ space: 5 }) {
Image($r('app.media.lovely1')).width('100%').height(200)
Button('全屏').onClick(() => {
ImmersionBar.init({ fullScreen: true })
}).width('80%')
Button('非全屏').onClick(() => {
ImmersionBar.init({ fullScreen: false })
}).width('80%')
Button('沉浸式').onClick(() => {
ImmersionBar.init({ immersion: true })
}).width('80%')
Button('非沉浸式').onClick(() => {
ImmersionBar.init({ immersion: false })
}).width('80%')
Button('沉浸式 并且设置 状态栏颜色').onClick(() => {
ImmersionBar.init({
immersion: true,
statusBarColor: '#FF0000',
statusBarContentColor: '#ff0048ff'
})
}).width('80%')
Button('获取状态栏、导航条(导航栏)高度').onClick(() => {
// 如果是在全屏模式下面,那么下面着四个个降全是0
ImmersionBar.getStatusHeight().then((height: number) => {
Logger.info(`状态栏的高度 = ${height} 单位vp`)
})
ImmersionBar.getNavigationBarHeight().then((height: number) => {
Logger.info(`导航栏的高度 = ${height} 单位vp`)
})
ImmersionBar.getNavigationIndicatorHeight().then((height: number) => {
Logger.info(`导航条的高度 = ${height} 单位vp`)
})
ImmersionBar.getNavigationHeight().then((height: number) => {
// 有时候咱们不关心到底是导航栏还是导航条,我们只想做沉浸式,可以使用此方法
Logger.info(`导航条+导航栏的高度 = ${height} 单位vp`)
})
}).width('80%')
Button('使用with绑定window').onClick(() => {
window.getLastWindow(getContext(this)).then((window) => {
ImmersionBar.with(window).setImmersion()
})
}).width('80%')
}
.height('100%')
.width('100%')
.backgroundColor(Color.Gray)