HarmonyOS NEXT 设置自定义状态栏(背景)解决方案

1,479 阅读3分钟

最近一直在研究鸿蒙上层应用开发,界面设计还算顺利,我一般习惯将整个页面的背景颜色设置为#F0F2F5,查阅了大量文档,并没有发现解决方案,经过一系列的捣鼓,终于有了头绪,下面我来总结一下思路。

需求描述

在日常开发中,很多APP选择使用灰色背景作为底色,白色卡片就能显示得更漂亮;而鸿蒙系统自带上下安全边距,使得我们无法控制上下安全距离内的元素。

解决思路

第一步:在合适的生命周期中开启全屏模式(关闭上下安全距离)

第二步:获取到上下安全距离存储到LocalStorage中,也就是本地持久化存储一下

第三步:自定义安全区域内容,保证显示正常

解决方案

  1. 编写安全区域管理类,包含 设置全屏模式(沉浸式)、获取顶部安全区域高度、获取底部安全区域高度

  2. 在需要的生命周期调用实例方法

  3. 自定义安全区域填充

实施方案

  1. 编写安全区域管理类,包含 设置全屏模式(沉浸式)、获取顶部安全区域高度、获取底部安全区域高度

我这里存放的位置为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. 在需要的生命周期调用实例方法

(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. 编写页面逻辑,自定义安全区域填充

(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%')
  }
}