androidkotlinuser-interfaceandroid-windowmanagerandroid-window

Adjust UI when system bars are showing Android


I am using this code to hide the status bar and navigation bar from the app:

val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())

But is there any way to prevent the navigation and status bar from showing above my app content?

Am I able to detect when the status bar is going to appear to set a padding/margin on the top view to prevent it from hiding my views?

If I could at least get the statusBar or navigationBar visibility could I prevent this behavior by applying an animation on the views (to go up or down and leave the space for status/navigation bar?


Solution

  • But is there any way to prevent the navigation and status bar from showing above my app content?

    If the user intentionally drag the top or the bottom of the screen to show the system bars; then no way to to prevent the navigation and status bars from showing above the app's content. Why? Because this drag is a part of system UI, not your app's window; check this answer for more in detail.

    But, if the developer intentionally show these bars, then yes margins can be added to these bars to prevent overlapping with the app's content.

    To get the height of these bars; register WindowInsetsListener to the root ViewGroup of your app, and get that from the insets.

    Here is a demo:

    var bottomNavigationHeight = 0
    var statusBarHeight = 0
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        setContentView(R.layout.activity_main)
        val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
        windowInsetsController.systemBarsBehavior =
            WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
    
    
        // root ViewGroup of the activity
        val root = findViewById<ConstraintLayout>(R.id.root)
        val onApplyWindowInsetsListener =
            OnApplyWindowInsetsListener { _: View?, windowInsets: WindowInsetsCompat ->
                val insets =
                    windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
                bottomNavigationHeight = insets.bottom
                statusBarHeight = insets.top
    
                WindowInsetsCompat.CONSUMED
            }
        ViewCompat.setOnApplyWindowInsetsListener(root, onApplyWindowInsetsListener)
    
        // some button to show up the system bars
        findViewById<Button>(...).setOnClickListener {
    
            // apply the margin to the system bars
            (root.layoutParams as FrameLayout.LayoutParams).apply {
                topMargin = statusBarHeight
                bottomMargin = bottomNavigationHeight
            }
    
            // show the system bars
            windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
    
        }
    }