Search code examples
androidandroid-statusbarandroid-15

How to preserve the space of the status bar? (Android 15+)


Android 15 suggests to use enableEdgeToEdge(), but this removes the top offset of the status bar, causing the main content to overlap with it.

What is the best way to preserve the height of the status bar? Just leave it transparent and render contents below it.

This is my attempt, it works but it's a lot of code, is there any simpler way?

// in the MainActivity.onCreate():

enableEdgeToEdge()

// the callback will be invoked repeatedly, use this flag to only set the margin-top once
var offsetAdjusted = false

window.decorView.setOnApplyWindowInsetsListener { _, insets ->
    if (!offsetAdjusted) {
        offsetAdjusted = true

        val top = if(Build.VERSION.SDK_INT > Def.ANDROID_10) // for android > 10
            insets.getInsetsIgnoringVisibility(WindowInsets.Type.statusBars()).top
        else // for android 10
            view.rootWindowInsets.stableInsetTop

        // the fragment container, which is a FragmentContainerView
        val container = binding.root.findViewById<FragmentContainerView>(R.id.nav_host_fragment_activity_main)

        val params = container.layoutParams as ViewGroup.MarginLayoutParams
        params.topMargin = top
        container.layoutParams = params
    }

    insets
}

Solution

  • EDIT: Seems like there's a way to opt out of this as well temporarily. Not recommended but it's there

    Using the flag windowOptOutEdgeToEdgeEnforcement which can be true/false Description can be found here

    There are many ways possible to do this

    There is a flag called fitsSystemWindows which can be set to true in your AndroidManifest.xml if it's just the status bar ( the one on the top ) you're targeting. See here

    Another approach, which is very similar to what you've done is using the setOnApplyWindowInsetsListener

    You can also return WindowInsetsCompat.CONSUMED if you consume it, so that it doesn't trigger the code repeatedly

    
    ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets ->
      val bars = insets.getInsets(
        WindowInsetsCompat.Type.systemBars()
          or WindowInsetsCompat.Type.displayCutout()
      )
      v.updatePadding(
        left = bars.left,
        top = bars.top,
        right = bars.right,
        bottom = bars.bottom,
      )
      WindowInsetsCompat.CONSUMED
    }
    
    

    You can give the section here a read once as well Hope this helps