Skip to content

沉浸式状态栏

实现沉浸式状态栏的核心是 window API 和 AppStorage 的系统安全区域。


1. 沉浸式状态栏的概念

传统状态栏          沉浸式状态栏
┌────────────────┐  ┌────────────────┐
│  状态栏(系统)   │  │  (无状态栏)     │
├────────────────┤  │                │
│                │  │                │
│    内容区域     │  │    内容区域     │
│                │  │    延伸到顶部   │
│                │  │                │
└────────────────┘  └────────────────┘

2. 全屏布局实现

2.1 基本方法

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

@Entry
@Component
struct Index {
    aboutToAppear() {
        // 开启全屏
        window.getWindowExtension().setWindowLayoutFullScreen(true)

        // 获取安全区域(避免刘海屏/圆角遮挡)
        let safeArea = window.getWindowExtension().getStatusBarHeight()
        console.log('状态栏高度:', safeArea)
    }

    build() {
        Column() {
            // 顶部内容延伸到状态栏下方
            Image('banner.jpg')
                .width('100%')
                .height(250)
                .objectFit(ImageFit.Cover)
        }
        .width('100%')
        .height('100%')
    }
}

3. 安全区域适配

3.1 使用 systemSafeArea

typescript
// 通过 AppStorage 获取安全区域信息
let statusBarHeight: number = AppStorage.get('systemStatusBarHeight') ?? 0
let navigationBarHeight: number = AppStorage.get('systemNavigationBarHeight') ?? 0
let safeAreaInsets: SafeAreaInsets = AppStorage.get('systemSafeArea') ?? {
    top: 0,
    bottom: 0,
    left: 0,
    right: 0
}

@Entry
@Component
struct Index {
    // 通过 AppStorage 获取安全区域
    @State statusBarHeight: number = 0

    aboutToAppear() {
        // 监听系统安全区域变化
        AppStorage.on('systemStatusBarHeight', (value: number) => {
            this.statusBarHeight = value
        })

        // 开启全屏
        window.getWindowExtension().setWindowLayoutFullScreen(true)
    }

    build() {
        Column() {
            // 预留状态栏高度
            Blank()
                .height(this.statusBarHeight)

            // 内容区域
            Image('banner.jpg')
                .width('100%')
                .height(200)
                .objectFit(ImageFit.Cover)

            Text('内容区域从安全区域开始')
                .padding({ top: this.statusBarHeight })
        }
        .width('100%')
        .height('100%')
    }
}

3.2 AppStorage 获取安全区域的方法

typescript
// 方式1:通过 window API
import { window } from '@kit.ArkUI'
let statusBarHeight = window.getWindowExtension().getStatusBarHeight()
let navigationBarHeight = window.getWindowExtension().getNavigationBarHeight()

// 方式2:通过 AppStorage(响应式,推荐)
let safeArea = AppStorage.get('systemSafeArea')

4. 导航栏避让

4.1 底部导航栏避让

typescript
@Entry
@Component
struct Index {
    @State safeAreaInsets: SafeAreaInsets = { top: 0, bottom: 0, left: 0, right: 0 }

    aboutToAppear() {
        window.getWindowExtension().setWindowLayoutFullScreen(true)

        // 监听安全区域变化
        AppStorage.on('systemSafeArea', (value: SafeAreaInsets) => {
            this.safeAreaInsets = value
        })
    }

    build() {
        Column() {
            // 顶部避让
            Blank()
                .height(this.safeAreaInsets.top)

            // 主内容
            Scroll() {
                Column() {
                    ForEach(this.items, (item: string) => {
                        Text(item)
                            .fontSize(16fp)
                            .padding({ top: 12, bottom: 12 })
                    })
                }
            }
            .width('100%')
            .layoutWeight(1)

            // 底部导航栏(在安全区域内)
            Row() {
                TabItem({ title: '首页', icon: $r('app.media.home') })
                TabItem({ title: '发现', icon: $r('app.media.discover') })
                TabItem({ title: '我的', icon: $r('app.media.profile') })
            }
            .height(56 + this.safeAreaInsets.bottom)
            .padding({ bottom: this.safeAreaInsets.bottom })
            .backgroundColor(Color.White)
        }
        .width('100%')
        .height('100%')
    }
}

5. 刘海屏/圆角屏适配

5.1 检测刘海屏

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

@Entry
@Component
struct Index {
    @State hasNotch: boolean = false

    aboutToAppear() {
        // 检测是否有刘海屏
        let notchScreenInfo = window.getWindowExtension().getNotchScreenInfo()
        this.hasNotch = notchScreenInfo.hasNotch

        if (this.hasNotch) {
            console.log('刘海屏信息:', JSON.stringify(notchScreenInfo.notch))
        }
    }

    build() {
        Column() {
            if (this.hasNotch) {
                Text('检测到刘海屏,需要避让')
                    .fontColor(Color.Red)
            }

            // 内容从安全区域开始
            Content()
        }
    }
}

6. 状态栏颜色设置

6.1 状态栏文字颜色

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

@Entry
@Component
struct Index {
    aboutToAppear() {
        window.getWindowExtension().setWindowLayoutFullScreen(true)

        // 浅色状态栏文字(深色图标)
        window.getWindowExtension().setColorMode(ColorMode.Light)

        // 或深色状态栏文字(浅色图标)
        // window.getWindowExtension().setColorMode(ColorMode.Dark)
    }

    build() {
        // 内容
    }
}

6.2 状态栏背景色

typescript
// 通过设置顶部区域的颜色来实现
Column() {
    Column()
        .height(statusBarHeight)
        .backgroundColor(Color.FromRGB(0x1A, 0x1A, 0x2E))

    // 内容
}

7. 完整的沉浸式示例

typescript
@Entry
@Component
struct ImmersivePage {
    @State statusBarHeight: number = 0
    @State navigationBarHeight: number = 0
    @State safeArea: SafeAreaInsets = { top: 0, bottom: 0, left: 0, right: 0 }

    aboutToAppear() {
        // 开启全屏
        window.getWindowExtension().setWindowLayoutFullScreen(true)

        // 获取安全区域
        AppStorage.on('systemStatusBarHeight', (value: number) => {
            this.statusBarHeight = value
        })

        AppStorage.on('systemSafeArea', (value: SafeAreaInsets) => {
            this.safeArea = value
        })

        AppStorage.on('systemNavigationBarHeight', (value: number) => {
            this.navigationBarHeight = value
        })
    }

    build() {
        Column() {
            // 状态栏避让区
            Blank()
                .height(this.statusBarHeight)

            // 全屏 Banner
            Stack() {
                Image('banner.jpg')
                    .width('100%')
                    .height(200)
                    .objectFit(ImageFit.Cover)
                Text('沉浸式标题')
                    .fontSize(24fp)
                    .fontColor(Color.White)
                    .position({ x: 16, y: this.statusBarHeight + 60 })
            }

            // 内容区域
            Scroll() {
                Column() {
                    ForEach(this.items, (item: string) => {
                        Text(item)
                            .fontSize(16fp)
                            .padding({ top: 12, bottom: 12, left: 16, right: 16 })
                    })
                }
            }
            .width('100%')
            .layoutWeight(1)

            // 底部避让区
            Blank()
                .height(this.navigationBarHeight)
        }
        .width('100%')
        .height('100%')
    }
}

8. 面试高频考点

Q1: 如何实现沉浸式状态栏?

回答:调用 window.setWindowLayoutFullScreen(true) 开启全屏,通过 AppStorage 获取 systemSafeArea 高度,给根布局设置 Padding 避让状态栏和导航栏。

Q2: 安全区域的作用?

回答:安全区域定义了屏幕的有效可视范围(排除状态栏、刘海屏、圆角、导航栏)。内容应该只在安全区域内,避免被系统 UI 遮挡。

Q3: 状态栏文字颜色如何设置?

回答:通过 window.getWindowExtension().setColorMode(ColorMode.Light/ColorMode.Dark) 设置浅色/深色状态栏文字模式。


🐱 小猫提示:沉浸式状态栏记住三步——开启全屏、获取安全区域、Padding 避让。安全区域用 AppStorage 响应式获取。