You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

API 30+如何检测应用是否处于Edge-to-Edge全屏模式?

解决Edge-to-Edge模式下的状态检测与Padding控制问题

核心问题分析

通过WindowCompat.setDecorFitsSystemWindows(window, false)实现Edge-to-Edge(全屏)模式后,在API30+版本中旧的systemUiVisibility标志已被废弃,无法用传统方式检测当前是否处于Edge-to-Edge状态;同时直接给decorView设置OnApplyWindowInsetsListener会打断系统默认的Insets传递逻辑,导致导航栏可见性检测失效,无法动态调整内容的底部padding。

可行解决方案

方案1:自行维护Edge-to-Edge状态变量(最简单直接)

既然Edge-to-Edge状态是通过自定义的fullScreen()和undoFullScreen()方法切换的,完全可以在Activity中维护一个状态变量,直接记录当前模式,无需依赖系统API检测。

修改代码如下:

  1. 在Activity中添加状态变量:
var isEdgeToEdgeEnabled: Boolean = false
    private set
  1. 更新扩展函数,同步状态变量:
fun Activity.fullScreen(isLightStatusBar: Boolean? = null) {
    window ?: return
    WindowCompat.setDecorFitsSystemWindows(window, false)
    isEdgeToEdgeEnabled = true

    // 可选:状态栏样式设置
    isLightStatusBar?.let {
        val controller = WindowCompat.getInsetsController(window, window.decorView)
        controller.isAppearanceLightStatusBars = it
    }

    if (Build.VERSION.SDK_INT >= 21) {
        window.statusBarColor = Color.TRANSPARENT
    }
}

fun Activity.undoFullScreen(isLightStatusBar: Boolean? = null) {
    window ?: return
    WindowCompat.setDecorFitsSystemWindows(window, true)
    isEdgeToEdgeEnabled = false

    // 可选:恢复状态栏样式
    isLightStatusBar?.let {
        val controller = WindowCompat.getInsetsController(window, window.decorView)
        controller.isAppearanceLightStatusBars = it
    }
}

之后需要判断状态时,直接使用isEdgeToEdgeEnabled变量即可,比如给内容设置padding:

if (isEdgeToEdgeEnabled) {
    binding.content.setPadding(0, 0, 0, navBarHeight)
} else {
    binding.content.setPadding(0, 0, 0, 0)
}

方案2:基于WindowInsets动态调整Padding(推荐,符合现代Android规范)

无需检测Edge-to-Edge状态,直接通过系统传递的WindowInsets动态调整内容的padding,这种方式完全兼容API30+及以下版本,且不需要维护额外状态。

关键注意点:不要给decorView设置OnApplyWindowInsetsListener,而是给内容容器(比如binding.content)设置,避免打断系统默认的Insets传递逻辑。

示例代码:

// 在Activity或Fragment的onViewCreated中设置
binding.content.setOnApplyWindowInsetsListener { view, insets ->
    val windowInsets = WindowInsetsCompat.toWindowInsetsCompat(insets)
    // 获取导航栏的底部Insets值
    val navBarBottomInset = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
    // 获取状态栏的顶部Insets值(如果需要处理状态栏遮挡)
    val statusBarTopInset = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars()).top

    // 动态设置内容的padding,避开系统栏
    view.setPadding(
        view.paddingLeft,
        statusBarTopInset,
        view.paddingRight,
        navBarBottomInset
    )

    // 返回CONSUMED表示已处理Insets,不再传递给子View;若需要子View处理,返回insets即可
    WindowInsetsCompat.CONSUMED
}

当setDecorFitsSystemWindows(window, false)时,系统会将系统栏的Insets传递给内容View,此时navBarBottomInset会是导航栏的实际高度,内容会自动添加padding避开导航栏;当切换回true时,系统会自动处理内容的padding,此时navBarBottomInset会变为0,内容的底部padding也会恢复正常,完全无需手动判断状态。

方案3:通过WindowInsetsController判断系统栏可见性(针对隐藏系统栏的场景)

如果你的场景是完全隐藏系统栏(而非Edge-to-Edge延伸),可以通过WindowInsetsController检测系统栏的可见性:

val controller = WindowCompat.getInsetsController(window, window.decorView)
val isNavBarVisible = controller.isVisible(WindowInsetsCompat.Type.navigationBars())
val isStatusBarVisible = controller.isVisible(WindowInsetsCompat.Type.statusBars())

注意:这仅适用于系统栏被完全隐藏的情况,Edge-to-Edge模式下系统栏仍可见,此方法无法区分是否处于Edge-to-Edge状态。

额外说明

  • API29及以下版本的Insets处理差异,使用WindowInsetsCompat可以自动兼容,无需单独做版本判断。
  • 避免混合使用setSystemUiVisibility和WindowCompat.setDecorFitsSystemWindows,官方明确说明两者会冲突,导致异常行为。

内容的提问来源于stack exchange,提问作者eddym

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 19:55:02