32

Working on a client's app that is using immersive mode to hide the navigation bar and status bar on every activity using the following code:

int currentApiVersion = android.os.Build.VERSION.SDK_INT;

final int flags = 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;

// This work only for android 4.4+
if (currentApiVersion >= 19) {

        getWindow().getDecorView().setSystemUiVisibility(flags);
        // Code below is for case when you press Volume up or Volume down.
        // Without this after pressing valume buttons navigation bar will
        // show up and don't hide
        final View decorView = getWindow().getDecorView();
        decorView
                .setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {

                    @Override
                    public void onSystemUiVisibilityChange(int visibility) {
                        if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                            decorView.setSystemUiVisibility(flags);
                        }
                }
         });
}

The only problem is that they would like the app to stay in immersive mode and not show the navigation bar even when the soft keyboard is showing to type into an EditText. Can anyone think of a way to always have the navigation buttons (back/hide keyboard, home, etc) always be hidden even while using the keyboard?

Chris Klingler
  • 5,258
  • 2
  • 37
  • 43
  • 1
    I am facing the same problem as we speak. I've tried about every hack I could conjure up. It's like the nav bar is tethered to the soft keyboard. Did you ever find a way? – a54studio Jan 20 '15 at 15:25
  • 2
    No I did not. The navigation is part of the soft keyboard. You can create your own custom keyboard that can show while still in immersive mode but it loses a lot of the functionality while in immersive mode that you need for a keyboard. So currently it seems there is no good way to type while staying in immersive mode. Lets hope there comes a way to do so in the future. If anyone knows of a way let us know. – Chris Klingler Jan 20 '15 at 17:22
  • 1
    The only thing I can come up with is creating your own keyboard functionality. I don't think you can hide the navigation bar while using Android keyboards. – Rudey Feb 10 '15 at 21:39
  • Does this answer your question? [Sticky immersive mode disabled after soft keyboard shown](https://stackoverflow.com/questions/24187728/sticky-immersive-mode-disabled-after-soft-keyboard-shown) – TylerH Oct 13 '22 at 18:00

5 Answers5

12

I've come up with a workaround that checks the navigation bar's status for every internal, try to hide it and check it again (and again).

Here's some piece of code, that makes sure the navigation bar is hidden in 2 seconds after the soft keyboard is closed.

  private final Runnable checkSystemUiRunnable = new Runnable() {
    @Override
    public void run() {
      checkHideSystemUI();
    }
  };

  private void checkHideSystemUI() {
    // Check if system UI is shown and hide it by post a delayed handler
    if (isSystemUiShown) {
      hideSystemUI();
      handler.postDelayed(checkSystemUiRunnable, SYSTEM_UI_HIDE_DELAY);
    }
  }

  private void hideSystemUI() {
    decorView.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);
  }

  // In onCreate()
    decorView.setOnSystemUiVisibilityChangeListener(
            new View.OnSystemUiVisibilityChangeListener() {
              @Override
              public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                  handler.postDelayed(checkSystemUiRunnable, SYSTEM_UI_HIDE_DELAY);
                  isSystemUiShown = true;
                } else {
                  isSystemUiShown = false;
                }
              }
            });
Mine
  • 4,123
  • 1
  • 25
  • 46
  • I found this to be a strange way to write the code, and it's missing a piece that handles app-switching or activity-switching. See the solution here and especially the last comment on it: http://stackoverflow.com/a/21253443/358578 – pbristow Mar 24 '16 at 15:40
  • Thanks buddy, u saved my time. – Rameshbabu May 19 '17 at 15:09
6

Here is my solution for this ; First I checked if soft keyboard is showed up or not:

getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                Rect r = new Rect();
                getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
                int screenHeight = getWindow().getDecorView().getRootView().getHeight();

                int keypadHeight = screenHeight - r.bottom;

                //Log.d(TAG, "keypadHeight = " + keypadHeight);

                if (keypadHeight > screenHeight * 0.15) { 
                     //Keyboard is opened
                     hideNavBar();
                }
                else {
                    // keyboard is closed
                }
            }
        });

And I have a hideNavBar() method to be triggered when soft keyboard is showed up.

private void hideNavBar() {
    if (Build.VERSION.SDK_INT >= 19) {
        View v = getWindow().getDecorView();
        v.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);
    }
}

This solves the problem of getting navigation bar while there is an Edittext to be typed.

Cem U
  • 893
  • 7
  • 14
1

Updated:

I have a painting app (Paint Shapes) and this is the configuration I used to always be inside the immersive mode. I use the onWindowFocusChanged method.

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && 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);
    }
}
Benny
  • 1,650
  • 17
  • 20
  • 1
    @ahmednabil88, thanks for the feedback, I just updated to put the configuration I actually use in my personal app. – Benny Feb 20 '19 at 23:10
0

I think that is not possible. Here

Flutter: How to show onscreen keyboard without android's bottom navigation bar on focusing a textfield?

is stated clearly and my experience seems to confirm it.

the following code placed in an activity

private var appVisibility:Int = (  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                                or View.SYSTEM_UI_FLAG_LOW_PROFILE
                                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                                or View.SYSTEM_UI_FLAG_FULLSCREEN
                                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    window.decorView.systemUiVisibility = appVisibility

}
override fun onResume() {
    super.onResume()
    updateUI()
}
fun updateUI() {
    val decorView = window.decorView
    decorView.setOnSystemUiVisibilityChangeListener { visibility ->
        if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
            decorView.systemUiVisibility = appVisibility
        }
    }
}

correctly hides the nav bar always (when you swipe from the bottom of the screen nav bar appears for a couple of seconds and then disappears) but when keyboard is on. I also tried to open keyboard programmatically and then hide the nav bar after few seconds, without any success.

private fun toggleIME(){
    val imm             = applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?
    val view: EditText? = text

    if(view != null && imm != null) {
        isKOpen = !isKOpen
        if (isKOpen) {
            view.requestFocus()
            imm.showSoftInput(view, InputMethodManager.SHOW_FORCED)

            handler.postDelayed(Runnable { // execute after XXXms
                updateUI()
                window.decorView.systemUiVisibility = appVisibility
            }, 5000)

        }
        else {
            imm.hideSoftInputFromWindow(view.windowToken, 0)
        }
    }
}

I hope to be missing something. I would need that for a custom keyboard I'm developing (where I have to implement the back button)

albaspazio
  • 121
  • 1
  • 6
0

The most efficient way is to set the SystemUIVisibility only when is needed:

  1. In your onCreate()
  2. With OnSystemUIChangeListener when the fullscreen mode is lost

The solution I use and recommend:

public class BaseActivity extends Activity {

    @SuppressLint("InlinedApi")
    private static final int UI_OPTIONS = View.SYSTEM_UI_FLAG_LOW_PROFILE
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;        

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Step 1
        hideSystemUI();

        // Step 2
        getWindow().getDecorView()
                   .setOnSystemUiVisibilityChangeListener(new View
                   .OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                    hideSystemUI();
                }
            }
        });
    }
    
    private void hideSystemUI() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) actionBar.hide();
        getWindow().getDecorView().setSystemUiVisibility(UI_OPTIONS);
    }

}