A fully Immersive fragment doesn't always hide the StatusBar when first launched

Graham McKechnie 441 Reputation points
2022-11-19T07:29:54.867+00:00

Since Android 11 the correct way of displaying a fully immersive fragment is by hiding and showing StatusBar and NavigationBars via the following code which fully supports all devices with a camera notch, at any API level. Note the WindowCompat version replaces the framework version, so you don’t need to check for a particular API level as you did when using the framework version.

Hide

WindowCompat.SetDecorFitsSystemWindows(Activity.Window, false);     
WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.GetInsetsController(Activity.Window, Activity.Window.DecorView);  
windowInsetsControllerCompat.SystemBarsBehavior = WindowInsetsControllerCompat.BehaviorShowTransientBarsBySwipe;  
windowInsetsControllerCompat.Hide(WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars());  

Show

WindowCompat.SetDecorFitsSystemWindows(Activity.Window, true);   
WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.GetInsetsController(Activity.Window, Activity.Window.DecorView);  
windowInsetsControllerCompat.Show(WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars());  

I was attempting to provide a choice of either displaying all fragments fully immersive or allowing other fragments to display as “letterboxed” i.e. not allowing the window to render into the DisplayCutout areas. So my existing preference choice "Devices with Notches/Cutouts allow full-screen display would have to change to support multiple choice".

The problem I hit was that the code I had used (like the WindowCompat code above since Android 11) was failing to display the fragment fullscreen when first launched. When it opened for the first time the window would attempt to go full screen, but only the NavigationBar would be removed. The StatusBar area was left as a black rectangle. You could see the animation of the time on the left and the icons on the right side of the StatusBar disappearing, (statusBar contents removed) but the window didn’t render into the StatusBar area. When rotated, the fragment became full screen and when rotated back to Portrait it corrected itself and was full screen again.

So in frustration, I went hunting on StackOverFlow looking for a solution but everything I found suggested that my ImmersiveFragment class was coded correctly. Then because this was my first attempt at using Material 3, I then started to suspect Material3, so I went backwards to my NavigationGraph6 project (Material2) and after much testing, I was able to reproduce the same problem, which obviously eliminated Material3.

More searching on StackOverflow and I came across a Kotlin post that was the same as all the others, except that it had the following line – equivalent to this C# line. Activity.Window.AddFlags(WindowManagerFlags.LayoutNoLimits)

So I added that line before the WindowCompat.SetDecorFitsSystemWindows(Activity.Window, false) in the HideSystemUi() and then cleared the flags before the WindowCompat.SetDecorFitsSystemWindows(Activity.Window, true) line in the ShowSystemUi with Activity.Window.ClearFlags(WindowManagerFlags.LayoutNoLimits) and immediately it worked.

So my question is why is this required and has anyone come across the same problem with immersive fragments?

Definition of LayoutNoLimits – Allow window to extend outside of the screen ???.

Does anyone have a clue what this definition actually means?

To test the code to make it fail (comment out the two new lines in ImmersiveFragment.cs). You can find the project, NavigationGraph7 at https://github.com/gmck/NavigationGraph7. For comparison, if you want, you can also download NavigationGraph6 to compare. The immersiveFragment is the RaceResultFragment (inherits from ImmersiveFragment) accessed by the BottomNavigationBar on the SlideShowFragment.

By the way, what happened to the Tag xamarin.android?

Developer technologies | .NET | Xamarin
{count} votes

1 answer

Sort by: Most helpful
  1. Graham McKechnie 441 Reputation points
    2022-11-24T21:54:14.36+00:00

    @Anonymous
    Thanks for downloading and testing the test apps.

    NavigationGraph7
    I think you will find that if it went full screen while both those lines were commented, then you also had "Devices with Notches/Cutouts allow full-screen display" checked also. Please try unchecking that preference and then confirm that the HomeFragment is "letterboxed" in Landscape, then rotate back to portrait and then attempt to open the RaceResultsFragment. You then should see the black rectangle.

    Since posting this thread, I altered the logic of that preference. See SetShortEdgesIfRequired() which is called at the end of OnDestinationChanged in the MainActivity. So now the condition for shortEdges is

    immersiveFragmentsDestinationIds.Contains<int>(navDestination.Id) | devicesWithNotchesAllowFullScreen  
    

    immersiveFragmentsDestinationIds looks a little odd here as a List, but in my real app, there are many more immersiveFragments.

    So now the users have a choice of all fragments being full-screen or "letterboxed" for the non-immersive fragments.

    Note: If you are not familiar with the NavigationComponent you may not realise that OnDestinationChanged is called even before the constructor of the destination fragment is called.

    I have an additional question for you. Yesterday I spend some time converting the NavigationGraph2 project from xamarin.android classic to net7.0-android. I'm writing up the steps I had to take to successfully convert it as it wasn't exactly straight forward. Here would seem an ideal place to share that knowledge, but when I posted some information here about the original NavigationComponent series - the forum stated that the post was not a question therefore against the rules and the topic would be closed.

    Can you suggest how a post like that should be published to the Xamarin community?


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.