Home > Software design >  Android 11 Full screen with Coordinator layout status bar spacing issue
Android 11 Full screen with Coordinator layout status bar spacing issue

Time:10-03

I am facing an issue with the full-screen immersive mode in Android 11. My Main activity layout file look something like this,

<DrawerLayout .... android:fitsSystemWindows="true">
    <CoordinatorLayout>
          <AppBarLayout>
              <FragmentContainerView>

I am trying to show a full-screen mode from my Fragment. Pre Android 11, I used to call the below function from my Fragment's onCreate view

fun hideStatusBar (activity: AppCompatActivity?) {
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) }

I replaced that with,

fun hideStatusBar(activity: AppCompatActivity?) {
@Suppress("DEPRECATION")
if (isAtLeastAndroid11()) {
    val controller = activity?.window?.insetsController
    controller?.hide(WindowInsets.Type.statusBars())
} else {
    activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
}
}

This removes the status bar as intended but leaves a blank space at the top of the screen in the status bar area

With status bar:

enter image description here

Status bar removed:

enter image description here

I tried to measure the Window Insets inside my fragment and adjust the height of my fragment container

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    if(isAtLeastAndroid11()){
        WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false)
        setUiWindowInsets()
    }
}

private fun setUiWindowInsets() {
    ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
    
        posTop = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
        posBottom = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom

        rootView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
            updateMargins(
                top = posTop,
                bottom = posBottom)
        }

        insets
    }
}

But my ViewCompat.setOnApplyWindowInsetsListener is never called. As per this article, Coordinator Layout consumes onApplyWindowInsets callbacks and the child won't get any callbacks. rootView is the root view of my Fragment (a relative layout) which was placed in FragmentContainer in my layout hierarchy.

Comparison between Android 10 and 11

enter image description here

My Question:

  1. How should I get the call to my setOnApplyWindowInsetsListener method in fragment?
  2. How should I let my coordinator layout know to occupy full screen when status bar is hidden?

References: Coordinator layout consumes callbacks:

  1. setOnApplyWindowInsetsListener never called
  2. https://medium.com/androiddevelopers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec
  3. https://newbedev.com/fitssystemwindows-effect-gone-for-fragments-added-via-fragmenttransaction

CodePudding user response:

The problem is from the App bar. even though it is full screen it will try to prevent content from colliding with status bar even if it is hidden. this is a new implementation also to prevent the phone notch from covering content.

You should remove the app bar if you want to utilize the whole screen. if really need a tooltip for actions use a bottom bar.

CodePudding user response:

You may have to set fitsSystemWindows flag off (where window is Window instance):

window.setDecorFitsSystemWindows(false);

So I do like this:

private void hideSystemUI() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        windowInsetsController.hide(WindowInsets.Type.statusBars());
        window.setDecorFitsSystemWindows(false);
    }
}

Of course, you also need to set the flag on when showing status bar:

private void showSystemUI() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        windowInsetsController.show(WindowInsets.Type.statusBars());
        window.setDecorFitsSystemWindows(true);
    }
}

FYI, you may have to trigger hideSystemUI or showSystemUI in Activity.onWindowFocusChanged.

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    if (hasFocus) {
        if (isImmersive) {
            hideSystemUI();
        } else {
            showSystemUI();
        }
    }
}

(above is in Java. Please translate it into Kotlin)

  • Related