HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航 原创

怀男孩cc
发布于 2025-3-19 11:05
浏览
0收藏

沉浸式状态栏导航

一、概念

沉浸式状态栏是一种让应用与系统UI融合的设计手法,通常指状态栏透明或与应用背景色一致,使得应用界面看起来更加统一和流畅。

二、实现沉浸式状态栏的原因

  1. 提升视觉体验:减少视觉割裂感,增强沉浸感。
  2. 优化界面空间:隐藏状态栏或透明化状态栏,扩大应用内容区域。
  3. 减少用户干扰:让用户更专注于应用内容,避免状态栏信息的分散注意力。
  4. 符合设计趋势:提升应用的现代感与专业性。

三、实现方式

HarmonyOS (ArkTS)

第一步
直接在 入口函数的EntryAbility里面进行配置,开启全屏显示

// 开启全屏沉浸式导航模式
const win = windowStage.getMainWindowSync()
win.setWindowLayoutFullScreen(true)

// 获取顶部规避区域,并记录到 AppStorage 中
const top = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)
  .topRect
AppStorage.setOrCreate<number>('safeTop', px2vp(top.height))
// 获取底部规避区域,并记录到 AppStorage 中
const bottom = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
  .bottomRect
AppStorage.setOrCreate<number>('safeBottom', px2vp(bottom.height))
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

放的位置:HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航-鸿蒙开发者社区

onWindowStageCreate
看一下前后效果
HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航-鸿蒙开发者社区

HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航-鸿蒙开发者社区

开启后发现
组件占位被状态栏遮盖,以及下面的导航条,此时接着下一步

第二步

第一步我们不仅开启了全屏显示,其实还做了一件事就是我们获取并储存了顶部和底部的安全距离,
接下来就是在组件里用起来就🆗了
HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航-鸿蒙开发者社区

  • 顶部规避区域:使用 win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM) 获取系统的规避区域(如状态栏的区域),并取出其顶部矩形的高度 (topRect.height),再将其通过 px2vp 转换为可视单位,最后存入 AppStorage 中,键名为 'safeTop'

  • 底部规避区域:使用 win.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) 获取导航栏指示器的规避区域,取出其底部矩形的高度 (bottomRect.height),同样通过 px2vp 转换,并存入 AppStorage 中,键名为 'safeBottom'
    这里我简单示范:

@Entry
@Component
struct Index { 
  //底部安全距离
  @StorageProp('safeBottom') safeBottom: number = 0
  //顶部导航栏高度
  @StorageProp('safeTop') safeTop: number = 0
  tabs: string[] = ['首页', '消息', '我的'];
  build() {
    Navigation() {
      Tabs({ barPosition: BarPosition.End }) {
        ForEach(this.tabs, (item: string, index) => {
          TabContent() {
            if (index === 0) {
              Text('首页')
            } else if (index === 1) {
              Text('消息')
            } else {
              Column() {
                Text('我的导航栏')
                  .width('100%')
                  .height(60)
                  .textAlign(TextAlign.Center)
                  .backgroundColor('rgba(214, 108, 108, 1.00)')
                .padding({ top: this.safeTop })
              }
              .width('100%')
              .height('100%')
              .backgroundColor(Color.Orange)
            }
          }.tabBar(item)
        })
      }
    }.hideTitleBar(true)
    .padding({ bottom: this.safeBottom })
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

效果展示:
HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航-鸿蒙开发者社区

两个步骤就完成了,如果说其他组件需要规避导航区域就直接使用AppStorage去拿到安全距离设一下padding就完事了

最后补充
其实也发现一些不足,很多时候我们这个状态栏是黑色不美观,我们还需要改一下这个状态栏的颜色
完成案例效果:
HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航-鸿蒙开发者社区
HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航-鸿蒙开发者社区

也是蛮常用的,具体实现呢也非常简单方法呢也不止一种,
首先是我这个案例由于我用的是一个页面,组件也没抽出去,所以组件页面没没办法用组件或者页面的生命周期函数,所以我用到的是onVisibleAreaChange
监听组件或页面的可见区域变化,并根据当前的可见性和可见区域的比例,动态调整状态栏内容的颜色。具体来说:

  1. onVisibleAreaChange:这个方法监听页面或组件的可见区域的变化,并传入两个参数:

    • [0.0, 1.0] :这是可见区域的比例范围,0.0 表示完全不可见,1.0 表示完全可见。
    • (isVisible: boolean, currentRatio: number) :回调函数,当可见性发生变化时触发。isVisible 表示当前元素是否可见,currentRatio 表示可见区域的比例。
  2. 状态栏颜色设置

    • 当组件完全可见时 (isVisible && currentRatio >= 1.0),调用 window.getLastWindow(getContext()) 来获取当前窗口实例,并将状态栏的内容颜色设置为白色 ('#FFFFFF')。
    • 当组件完全不可见时 (!isVisible && currentRatio <= 0.0),同样获取窗口实例,将状态栏的内容颜色设置为黑色 ('#000000')。
.onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => {
  if (isVisible && currentRatio >= 1.0) {
    window.getLastWindow(getContext())
      .then((win) => {
        win.setWindowSystemBarProperties({ statusBarContentColor: '#FFFFFF' })
      })
  }
  if (!isVisible && currentRatio <= 0.0) {
    window.getLastWindow(getContext())
      .then((win) => {
        win.setWindowSystemBarProperties({ statusBarContentColor: '#000000' })
      })
  }
})
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

完整示例代码:

import { window } from '@kit.ArkUI';

@Entry
@Component
struct Index { 
  //底部安全距离
  @StorageProp('safeBottom') safeBottom: number = 0
  //顶部导航栏高度
  @StorageProp('safeTop') safeTop: number = 0
  tabs: string[] = ['首页', '消息', '我的'];
  build() {
    Navigation() {
      Tabs({ barPosition: BarPosition.End }) {
        ForEach(this.tabs, (item: string, index) => {
          TabContent() {
            if (index === 0) {
              Text('首页')
            } else if (index === 1) {
              Text('消息')
            } else {
              Column() {
                Text('我的导航栏')
                  .width('100%')
                  .height(60)
                  .textAlign(TextAlign.Center)
                  .backgroundColor('rgba(214, 108, 108, 1.00)')
                .padding({ top: this.safeTop })
              }
              .width('100%')
              .height('100%')
              .backgroundColor(Color.Orange)
              .onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => {
                if (isVisible && currentRatio >= 1.0) {
                  window.getLastWindow(getContext())
                    .then((win) => {
                      win.setWindowSystemBarProperties({ statusBarContentColor: '#FFFFFF' })
                    })
                }
                if (!isVisible && currentRatio <= 0.0) {
                  window.getLastWindow(getContext())
                    .then((win) => {
                      win.setWindowSystemBarProperties({ statusBarContentColor: '#000000' })
                    })
                }
              })
            }
          }.tabBar(item)
        })
      }
    }.hideTitleBar(true)
    .padding({ bottom: this.safeBottom })
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.

效果展示:
HarmonyOS Next 教你两步超简单实现鸿蒙沉侵状态栏导航-鸿蒙开发者社区

还有一种呢就是非常常用组件或者页面的生命周期钩子上:

aboutToAppear(): void {
  window.getLastWindow(getContext())
    .then((win) => {
      win.setWindowSystemBarProperties({ statusBarContentColor: '#FFFFFF' })
    })
}

aboutToDisappear(): void {
  window.getLastWindow(getContext())
    .then((win) => {
      win.setWindowSystemBarProperties({ statusBarContentColor: '#000000' })
    })
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
onPageShow
(): void {
  window.getLastWindow(getContext())
    .then((win) => {
      win.setWindowSystemBarProperties({ statusBarContentColor: '#FFFFFF' })
    })
}

onPageHide
(): void {
  window.getLastWindow(getContext())
    .then((win) => {
      win.setWindowSystemBarProperties({ statusBarContentColor: '#000000' })
    })
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

实现的效果都是一样的,最后提醒一下,这个颜色必须写成'#FFFFFF''#000000'否则也会导致颜色没有变化,注意一下就好了反正我当时找半天找不出来哪的问题,还必须是6位写全

四、结语

沉浸式状态栏设计在现代应用中已经越来越普遍,尤其是全屏体验需求强烈的场景下,如媒体播放、游戏和浏览器。通过本文的实现步骤,我们可以看到,HarmonyOS 中提供的窗口管理接口十分灵活,能够轻松实现沉浸式状态栏导航效果,且具备极好的拓展性。开发者可以根据实际需求,对状态栏颜色、系统按钮显示进行进一步优化,为用户提供更统一、流畅的视觉体验。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2025-3-25 17:47:58修改
收藏
回复
举报
回复
    相关推荐