Android Immersive mode reset when changing activity
Asked Answered
I

5

6

I'm facing a problem when using immersive mode. Here is the code I put on all activities:

 @Override
 public void onWindowFocusChanged(boolean hasFocus) {
     super.onWindowFocusChanged(hasFocus);
     if (hasFocus) {
         getWindow().getDecorView().setSystemUiVisibility(
             View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                 | View.SYSTEM_UI_FLAG_FULLSCREEN
                 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
         );
     }
 }

The navigationBar and statusBar are invisible, this is good.

The problem is that every time I go to another activity, the navigationBar appears, then disappears. I would like that the navigationBar to not appear like that.

Inspissate answered 21/3, 2015 at 17:59 Comment(0)
S
6

The simplest working way is to create a base activity class like the following:

public abstract class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        enableImmersiveMode();
    }

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

        if(hasFocus) {
            enableImmersiveMode();
        }
    }

    protected void enableImmersiveMode() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            );
        }
    }
}

And all activities that should work in immersive mode should inherit from above base class.

I've just tested it. It prevents an on-screen menu to hide and reveal while changing activities.

Slowwitted answered 5/7, 2016 at 9:35 Comment(0)
D
3

If you invoque this short of code in method onCreate of activity like the next example:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            hideSystemUI();
            ...
   }

 // This snippet hides the system bars.
    private void hideSystemUI() {
        // Set the IMMERSIVE flag.
        // Set the content to appear under the system bars so that the content
        // doesn't resize when the system bars hide and show.
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
                        | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                        | View.SYSTEM_UI_FLAG_IMMERSIVE);
    }

And you must invoke the method on onWindowFocusChanged too.

I hope this help you =)

Domesticate answered 25/3, 2015 at 18:17 Comment(1)
Sorry but your solution do not fixes the problem. The navigation bar continues to appear and disappear every time I change Activity.Inspissate
R
3

maybe it's late but right now I faced same issue as you, and stumbled upon this post. By curiosity I found solution that worked for me. I manually called function "onWindowFocusChanged" and passed the "true" parameter. I called that function in OnCreate, before "setContentView(R.layout.activity_main);". That executed the function and set immersive mode (fullscreen), before layout was added, and now I don't see hiding animation of navigation and status bars. I hope that I helped you.

This is the code:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    onWindowFocusChanged(true);
    setContentView(R.layout.activity_main);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}
}
Ryanryann answered 6/1, 2017 at 20:58 Comment(0)
W
2

I was also faced with this issue. It seems there is no way to stop Android from showing the navigation bar again after the configuration changes.

What's worse, it is also not guaranteed when exactly the system UI will be restored. According to my tests on some devices the nav bar can reappear even after onWindowFocusChanged and onResume have been called.

The only reliable way I've found to prevent undesired UI reappearing is to add isInFullScreenModeboolean flag and implement View.OnSystemUiVisibilityChangeListener something like this:

@Override
public void onSystemBarsVisible() {
    if (isInFullScreenMode) {
        // If Android presented system bars 
        // but our app doesn't need them at this point 
        // just call hideSystemUi() again
        hideSystemUi();
        return;
    }
}

@Override
public void onSystemBarsHidden() {
    if (!isInFullScreenMode) {
        // Similar technique as shown above
        showSystemUi();
        return;
    }
}

Of course, sometimes on rotation we can see how the system bars quickly appear and disappear. But at least we can be sure that our app's UI state will be reliably restored.

Edit: To prevent possible confusion (as can be seen in the comments), I will clarify a couple of things:

  • onSystemBarsVisible and onSystemBarsHidden are custom methods which were defined in my app. You won't find them in Android frameworks;
  • The override keywords are used here because these methods were part of a contract (interface);
  • The app I used this functionality in is obsolete now. However, I still remember that the basic idea was as follows (snippet in Kotlin):
fun onSystemUiVisibilityChange(visibility: Int) {
    if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
        // The system bars are visible
        onSystemBarsVisible()
    } else {
        // The system bars are NOT visible.
        onSystemBarsHidden()
    }
}
Withdrew answered 14/3, 2017 at 18:46 Comment(3)
Can you give a more complete example? Those functions you override don't appear to exist in View.OnSystemUiVisibilityChangeListener.Topazolite
@Michael, I've added some explanations to the answer. Hope everything is clear now.Withdrew
thanks! this does seem to work, although it apparently kinda fights with attempts to swipe-expose navigations bars and the like when you actually need them (which is perhaps related to the whole obsolescence thing)Topazolite
G
0

The real solution is to call the setSystemUiVisibility on both onResume and onWindowFocusChanged.

@Override
protected void onResume() {
    super.onResume();
    hide();
}

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

public void hide() {
    getWindow().getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
            View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
            View.SYSTEM_UI_FLAG_FULLSCREEN |
            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE);           
}
Gravity answered 10/8, 2016 at 17:36 Comment(1)
Calling in onResume freezes app for meHalutz

© 2022 - 2024 — McMap. All rights reserved.