3

I have three fragments. I want to apply a transparent status bar on just one fragment. For that purpose, I am calling the following hide method on the setOnItemSelectedListener method of the bottom navigation bar. Also added an image of what I am getting right now

private fun hideStatusBar() {
    window.statusBarColor = ContextCompat.getColor(this@SuperActivity, R.color.transparent)
    WindowCompat.setDecorFitsSystemWindows(window, false)
    ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
      val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())

      view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
        leftMargin = insets.left
        rightMargin = insets.right
        bottomMargin = insets.bottom
      }
      WindowInsetsCompat.CONSUMED
    }
  }
    

  private fun showStatusBar() {
    window.statusBarColor = ContextCompat.getColor(this@SuperActivity, R.color.transparent)
    WindowCompat.setDecorFitsSystemWindows(window, true)
  }

I am getting the appropriate behavior on fragment calling hide method. enter image description here

But when I tap on another fragment (the one that needs to show the status bar), I get the following behaviour:

enter image description here

Zain
  • 37,492
  • 7
  • 60
  • 84
Taha Asif
  • 333
  • 6
  • 24
  • Did you revert back this `WindowCompat.setDecorFitsSystemWindows(window, false)` for the other fragments? – Zain Nov 11 '21 at 04:37
  • yes. As you can see in showStatusBar() method. I reverted this using WindowCompat.setDecorFitsSystemWindows(window, true) – Taha Asif Nov 11 '21 at 04:38

1 Answers1

1

The bottom margin by default is 0 (or the designated value in the root layout "binding.root")

So, you need to reset the bottom margin again; if it's already 0; then you can:

private fun showStatusBar() {
    window.statusBarColor = ContextCompat.getColor(this@SuperActivity, R.color.transparent)
    WindowCompat.setDecorFitsSystemWindows(window, true)

    ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
      val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())

      view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
        bottomMargin = 0 // reset the margin
      }
      WindowInsetsCompat.CONSUMED
    }
  }
}

Or if it's something else; then you need to convert that from dp to pixels and set it to the bottomMargin

The same thing applies if you have some designated margin values in binding.root; but I think you didn't as the issue only appears at the bottom.

UPDATE:

The method setOnApplyWindowInsetsListener is not called inside showStatusBar method. Because in this, the Window Insets are not changed. Since, we added margin in hideStatusBar method, so this space that you see below navigation bar is from hideStatusBar method.

Although the listener should be triggered, but you can update the root directly:

binding.root.updateLayoutParams<ViewGroup.MarginLayoutParams> {
    bottomMargin = 0
}

But notice that the setDecorFitsSystemWindows can take some time to update, so updateLayoutParams wouldn't have the effect, so, you might need a little delay for that:

Handler(Looper.getMainLooper()).postDelayed( {
    binding.root.updateLayoutParams<ViewGroup.MarginLayoutParams> {
        bottomMargin = 0
    }
 }, 0.1.toLong())
Zain
  • 37,492
  • 7
  • 60
  • 84
  • But it'd be better to have a single `ViewCompat.setOnApplyWindowInsetsListener` that handles both cases; you can do a simple condition on that – Zain Nov 11 '21 at 05:07
  • Nopes. The method setOnApplyWindowInsetsListener is not called inside showStatusBar method. Because in this, the Window Insets are not changed. Since, we added margin in hideStatusBar method, so this space that you see below navigation bar is from hideStatusBar method. That is the reason as to why I want to revert the window insets to initial one – Taha Asif Nov 11 '21 at 05:09
  • So, you'd try to directly call `binding.root.updateLayoutParams { bottomMargin = 0 // reset the margin }` on the root view. Although the above get called with my test – Zain Nov 11 '21 at 05:11
  • 1
    yeah. Thanks @Zain. That's the fix. Can you please update the last comment in your answer as well. So that I may approve it – Taha Asif Nov 11 '21 at 05:17
  • 1
    Welcome @TahaAsif.. But notice as this can differ from device to another. As per my test, calling that directly didn't have effect; I had to do a little delay on that; I updated the answer with that too – Zain Nov 11 '21 at 05:22
  • @TahaAsif I am sure you are testing that on API 30+, because `WindowInsetsCompat.CONSUMED` removes the `ViewCompat.setOnApplyWindowInsetsListener` on API 30+, and keeps it on below API 30. Now I am afraid that you would get unexpected behavior if you return back to the fragment that you'd need to hide the status bar on – Zain Nov 11 '21 at 05:40