1

Hello,

I am trying to make my android app fullscreen and hide the navigation bar.

It works well but I noticed that when I press a button on my custom toolbar the navigation bar reappears and stays visible. It has a solid black color, so it is not the "normal" semi-transparent version that briefly shows up if you swipe up from the bottom etc.

How can I make sure the bar stays hidden? And as a bonus question, is it possible to also hide the temporary semi-transparent version so the bar is completely removed?

I am using the following code in the activity to hide the NavigationBar, and create the toolbar:

    protected override void OnResume()
    {
        base.OnResume();
        WindowCompat.SetDecorFitsSystemWindows(Window, false);
        var windowInsetsControllerCompat = new WindowInsetsControllerCompat(Window, _MainContainer);
        windowInsetsControllerCompat.Hide(WindowInsetsCompat.Type.SystemBars() | WindowInsetsCompat.Type.NavigationBars());
        windowInsetsControllerCompat.SystemBarsBehavior = WindowInsetsControllerCompat.BehaviorShowTransientBarsBySwipe;
    }

    public override bool OnCreateOptionsMenu(IMenu menu)
    {
        MenuInflater.Inflate(Resource.Menu.custom_toolbar_menu, menu);
        return true;
    }

And my Menu looks like this:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/selectItem"
        android:icon="@drawable/select_item_48"
        android:title="@string/title_select_item"
        app:showAsAction="always">
    </item>
    
    <item
        android:id="@+id/moreVertical"
        android:icon="@drawable/baseline_more_vert_black_48"
        android:title="@string/more"
        app:showAsAction="always">
        <menu>
            <item
                android:id="@+id/logout"
                android:title="@string/title_logout"/>
        </menu>
    </item>
</menu>

EDIT

After moving my code to OnWindowFocusChanged instead it works better, but I still have a small back arrow visible while the focus change is happening. The bar itself is fully transparent and the app is still fullscreen, the only issue is that the back arrow for some reason is visible.

public override void OnWindowFocusChanged(bool hasFocus)
    {
        Log.Debug(Constants.TAG, $"SaleActivity OnWindowFocusChanged: {hasFocus}");
        base.OnWindowFocusChanged(hasFocus);

        WindowCompat.SetDecorFitsSystemWindows(Window, false);
        var windowInsetsControllerCompat = new WindowInsetsControllerCompat(Window, Window.DecorView);
        windowInsetsControllerCompat.Hide(WindowInsetsCompat.Type.SystemBars() | WindowInsetsCompat.Type.NavigationBars());
        windowInsetsControllerCompat.SystemBarsBehavior = WindowInsetsControllerCompat.BehaviorShowTransientBarsBySwipe;
    }
Taxen0
  • 55
  • 8

3 Answers3

0

At first, I had test the menu item and think that it is clicked, the system will call some method to show the navigation bar. So you can put the following code into the activity to make the navigation bar disaappear when the focused change.

  public override void OnWindowFocusChanged(bool hasFocus)
    {
        base.OnWindowFocusChanged(hasFocus);
        Window.SetFlags(WindowManagerFlags.Fullscreen, WindowManagerFlags.Fullscreen);

        Window.DecorView.SystemUiVisibility = (StatusBarVisibility)
                                 (SystemUiFlags.LowProfile
                                 | SystemUiFlags.Fullscreen
                                 | SystemUiFlags.HideNavigation
                                 | SystemUiFlags.Immersive
                                 | SystemUiFlags.ImmersiveSticky);
    }
Liyun Zhang - MSFT
  • 8,271
  • 1
  • 2
  • 14
  • 1
    Why post answers using code that was deprecated long ago? It should be obvious from the question that the user has moved on from that style of code. – user2153142 Apr 09 '22 at 00:35
  • thank you, but I would like to use the newer version using WindowCompat.SetDecorFitsSystemWindows(Window, false); if possible – Taxen0 Apr 11 '22 at 07:38
  • You can try it, the point of my answer is setting the full screen and hiding the navigation bar when the foucued changed. @Taxen0 – Liyun Zhang - MSFT Apr 11 '22 at 08:10
  • @LiyunZhang-MSFT thank you for the clarification, got confused by previous commenter and missed that you used OnWindowFocusChanged instead. After tying to add the code from my OnResume to OnWindowFocusChanged instead it works better, but the back button is still visible (but the bar itself is transparent and the app still expands the whole screen at least). any idea how to solve that? updated the post with my code – Taxen0 Apr 12 '22 at 07:37
  • I think this may be the best result. The probelm's cause might be the menu item clicked event which I can't find any way to override it and what I can do is just add a clicklistener to it. Such as `var item = menu.FindItem(Resource.Id.moreVertical); item.SetOnMenuItemClickListener(new MyMenuItemOnMenuItemClickListener(this));` @Taxen0 – Liyun Zhang - MSFT Apr 12 '22 at 10:04
  • So you can try to override the item clicked event if possible. I search for a long time and cann't do that. It may need to custom a menu class which extends the IMenu and then override the clicked event.@Taxen0 – Liyun Zhang - MSFT Apr 12 '22 at 10:09
0

@Taxen0 Have you tried?

windowInsetsControllerCompat.Hide(WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars());

When I first started using windowInsetsController, which was just after they first released AndroidX.Core - it was Android 11 if I remember correctly, it was always null, so I create one in OnStart.

I'm doing the following for fragments, so the following code is from a base class that any immersive fragment can inherit. Then, use OnResume and OnPause to control the hiding and showing.

public override void OnStart()
        {
            windowInsetsControllerCompat = new WindowInsetsControllerCompat(Activity.Window, Activity.Window.DecorView);
            if (Activity is MainActivity mainActivity)
            {
                mainActivity.SupportActionBar.Hide();
                mainActivity.DisableDrawerLayout();             // Disable the navigationDrawer of the MainActivity. We don't want a user to be able to swipe it into view while viewing any of the gauges
            }

            base.OnStart();
        }

public void HideSystemUi()
        {
            // 17/01/2021 Added this reference as an explanation of why we needed this code from Android 11 and on...
            // Don't use android:fitsSystemWindows="true" anywhere.
            // Refer to https://stackoverflow.com/questions/57293449/go-edge-to-edge-on-android-correctly-with-windowinsets/70714398#70714398 goto the bottom for this solution

            WindowCompat.SetDecorFitsSystemWindows(Activity.Window, false);
            //WindowInsetsControllerCompat windowInsetsControllerCompat = ViewCompat.GetWindowInsetsController(Activity.Window.DecorView); // Always null. Have to create our own
            windowInsetsControllerCompat.Hide(WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars());     
            windowInsetsControllerCompat.SystemBarsBehavior = WindowInsetsControllerCompat.BehaviorShowTransientBarsBySwipe;
        }

private void ShowSystemUi()
        {
            WindowCompat.SetDecorFitsSystemWindows(Activity.Window, true);
            //WindowInsetsControllerCompat windowInsetsControllerCompat = ViewCompat.GetWindowInsetsController(Activity.Window.DecorView);  // Always null. Have to create our own
            windowInsetsControllerCompat.Show(WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars());

            // 29/05/2021 This used to be before clearing the flags when we had them
            if (Activity is MainActivity mainActivity)
            {
                mainActivity.SupportActionBar.Show();
                mainActivity.EnableDrawerLayout();
            }
        } 

This works fine whether you are using gestures or a 3 button navigation bar.

user2153142
  • 431
  • 1
  • 4
  • 7
0

@Taxen0

You don't want

windowInsetsControllerCompat.Hide(WindowInsetsCompat.Type.SystemBars() | WindowInsetsCompat.Type.NavigationBars());

You do want

windowInsetsControllerCompat.Hide(WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars());

Prove it to yourself - in the debugger break on the line after the line above and get the value of WindowInsetsCompat.Type.SystemBars() | WindowInsetsCompat.Type.NavigationBars() in a watch window. You will find it is equal to 7

Now at the same time check the value of WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars(). You will find it is equal to 3

Your way will hide both bars, but when you swipe with BehaviorShowTransientBarsBySwipe when the bars are meant to hide again, the NavigationBar will remain, which is probably not what you want, because then your screen isn't fully immersive.

user2153142
  • 431
  • 1
  • 4
  • 7