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:
Status bar removed:
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
My Question:
- How should I get the call to my
setOnApplyWindowInsetsListener
method in fragment? - How should I let my coordinator layout know to occupy full screen when status bar is hidden?
References: Coordinator layout consumes callbacks:
- setOnApplyWindowInsetsListener never called
- https://medium.com/androiddevelopers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec
- 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)