Android: How to hide the System UI properly

16,115

Solution 1

I include this in every activity that I want to hide the nav bar and status bar:

    public void hideToolBr(){

        // BEGIN_INCLUDE (get_current_ui_flags)
        // The UI options currently enabled are represented by a bitfield.
        // getSystemUiVisibility() gives us that bitfield.
        int uiOptions = getWindow().getDecorView().getSystemUiVisibility();
        int newUiOptions = uiOptions;
        // END_INCLUDE (get_current_ui_flags)
        // BEGIN_INCLUDE (toggle_ui_flags)
        boolean isImmersiveModeEnabled =
                ((uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) == uiOptions);
        if (isImmersiveModeEnabled) {
            Log.i(Constants.TAG_DEF, "Turning immersive mode mode off. ");
        } else {
            Log.i(Constants.TAG_DEF, "Turning immersive mode mode on.");
        }

        // Navigation bar hiding:  Backwards compatible to ICS.
        if (Build.VERSION.SDK_INT >= 14) {
            newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
        }

        // Status bar hiding: Backwards compatible to Jellybean
        if (Build.VERSION.SDK_INT >= 16) {
            newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN;
        }

        // Immersive mode: Backward compatible to KitKat.
        // Note that this flag doesn't do anything by itself, it only augments the behavior
        // of HIDE_NAVIGATION and FLAG_FULLSCREEN.  For the purposes of this sample
        // all three flags are being toggled together.
        // Note that there are two immersive mode UI flags, one of which is referred to as "sticky".
        // Sticky immersive mode differs in that it makes the navigation and status bars
        // semi-transparent, and the UI flag does not get cleared when the user interacts with
        // the screen.
        if (Build.VERSION.SDK_INT >= 18) {
            newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
        }

        getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
        //END_INCLUDE (set_ui_flags)

    }

Then in my activity's onCreate method, I call this after setContentView()

hideToolBr();

Then all the user has to do is swipe up from the bottom or swipe down from the top to bring up the status bar or nav bar. Google calls this "immersive mode". It gives the developer full use of the devices' screen real-estate.

Taken from Googles example of immersive mode, calling this shows the system UI:

    // This snippet shows the system bars. It does this by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
    mDecorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}

You can find more information here.

Edit:

Add this to your styles.xml as well

    <style name="YourTheme.NoActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    <item name="android:colorForeground">@color/colorPrimaryDark</item>
</style>

Solution 2

Just call these methods when you want to hide/show the system UI.

private void hideSystemUI() {
    View decorView = getActivity().getWindow().getDecorView();
    int uiOptions = decorView.getSystemUiVisibility();
    int newUiOptions = uiOptions;
    newUiOptions |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
    newUiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
    newUiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
    newUiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE;
    newUiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    decorView.setSystemUiVisibility(newUiOptions);
}

private void showSystemUI() {
    View decorView = getActivity().getWindow().getDecorView();
    int uiOptions = decorView.getSystemUiVisibility();
    int newUiOptions = uiOptions;
    newUiOptions &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
    newUiOptions &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
    newUiOptions &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
    newUiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE;
    newUiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    decorView.setSystemUiVisibility(newUiOptions);
}
Share:
16,115
Oleg Ryabtsev
Author by

Oleg Ryabtsev

Updated on June 09, 2022

Comments

  • Oleg Ryabtsev
    Oleg Ryabtsev almost 2 years

    I'm developing a video player application and I've faced to a problem. I have a custom video controller which contains a fullscreen button and I want hide the System UI (navigation and status bars) when the user enters to fullscreen mode. I've tried to do something like this, but it doesn't work properly. My application is like the screenshot below:

    enter image description here

    When I click the fullscreen button, I change orientation to landscape and I hide the System UI, but my player doesn't get fullscreen. It looks like the screen below:

    Status bar hides and navigation bar hides too, but player doesn't take the whole screen

    Also, when I tap the screen I want to show my video controller, but the System UI shows the below content, instead:

    System UI shows when I tap on screen

    So, how can I implement this behavior? Below are my methods for fullscreen and hiding/showing the System UI:

    @Override
    public void toggleFullscreen() {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mVideoContainer.getLayoutParams();
        if (!mFullscreen) {
                 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
            hideSystemUI();
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            params.width = metrics.widthPixels;
            params.height = metrics.heightPixels;
            params.setMargins(0, 0, 0, 0);
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            showSystemUI();
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            params.width = metrics.widthPixels;
            params.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300, metrics);
                params.setMargins(0, 0, 0, 0);
        }
        mVideoContainer.setLayoutParams(params);
        mFullscreen = !mFullscreen;
    }
    
    private void hideSystemUI() {
        View decorView = getWindow().getDecorView();
        int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
        if (Build.VERSION.SDK_INT < 16) {
                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN)
        } else {
            uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
        }
        decorView.setSystemUiVisibility(uiOptions);
    }
    
    private void showSystemUI() {
        View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(0);
    }
    

    Here's my layout:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/video_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <FrameLayout
            android:id="@+id/videoSurfaceContainer"
            android:layout_width="match_parent"
            android:layout_height="300dp" >
    
            <SurfaceView
                android:id="@+id/videoSurface"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </FrameLayout>
    </LinearLayout>