6

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>

6 Answers 6

9

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>
Sign up to request clarification or add additional context in comments.

15 Comments

it still leaves empty space after entering to fullscreen at navigation bar's place :(
@OlegRyabtsev Does your layout match the parent in your xml android:layout_height="match_parent"?
I have a LinearLayout as a root layout with layout_height="match_parent", and inside this I have a FrameLayout with 300dp height. Inside FrameLayout is SurfaceView with width and height equal to match_parent. And I try change size of FrameLayout dynamically when click on fullscreen button
@OlegRyabtsev So your main LinearLayout fills the screen but your FrameLayout doesn't adjust to fill the space where the nav bar was. Is that correct?
@OlegRyabtsev Could you post the layout you're having problems with so I can test it?
|
6

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);
}

1 Comment

I had a problem that the titleBar would not hide, but it can be solved with getSupportActionBar().hide(); and getSupportActionBar().show(); for anyone who encounters the same issue
2

To hide system UI there is a clean and scalable approach I've come up recently with. It supports all Android versions including Api level 31, 30, and before that.

object SystemBarsCompat {
    private val api: Api =
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> Api31()
            Build.VERSION.SDK_INT == Build.VERSION_CODES.R -> Api30()
            else -> Api()
        }

    fun hideSystemBars(window: Window, view: View, isImmersiveStickyMode: Boolean = false) =
        api.hideSystemBars(window, view, isImmersiveStickyMode)

    fun showSystemBars(window: Window, view: View) = api.showSystemBars(window, view)

    fun areSystemBarsHidden(view: View): Boolean = api.areSystemBarsHidden(view)

    @Suppress("DEPRECATION")
    private open class Api {
        open fun hideSystemBars(window: Window, view: View, isImmersiveStickyMode: Boolean = false) {
            val flags = View.SYSTEM_UI_FLAG_FULLSCREEN or
                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION

            view.systemUiVisibility = if (isImmersiveStickyMode) {
                flags or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            } else {
                flags or
                    View.SYSTEM_UI_FLAG_IMMERSIVE or
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            }
        }

        open fun showSystemBars(window: Window, view: View) {
            view.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        }

        open fun areSystemBarsHidden(view: View) = view.systemUiVisibility and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION != 0
    }

    @Suppress("DEPRECATION")
    @RequiresApi(Build.VERSION_CODES.R)
    private open class Api30 : Api() {

        open val defaultSystemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE

        override fun hideSystemBars(window: Window, view: View, isImmersiveStickyMode: Boolean) {
            window.setDecorFitsSystemWindows(false)
            view.windowInsetsController?.let {
                it.systemBarsBehavior =
                    if (isImmersiveStickyMode) WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
                    else defaultSystemBarsBehavior
                it.hide(WindowInsets.Type.systemBars())
            }
        }

        override fun showSystemBars(window: Window, view: View) {
            window.setDecorFitsSystemWindows(false)
            view.windowInsetsController?.show(WindowInsets.Type.systemBars())
        }

        override fun areSystemBarsHidden(view: View) = !view.rootWindowInsets.isVisible(WindowInsets.Type.navigationBars())
    }

    @RequiresApi(Build.VERSION_CODES.S)
    private class Api31 : Api30() {
        override val defaultSystemBarsBehavior = WindowInsetsController.BEHAVIOR_DEFAULT
    }
}

And for example to hide system bars, it can be called from a Fragment:

SystemBarsCompat.hideSystemBars(requireActivity().window, view)

Comments

1
**For Kotlin:** 

  private fun hideSystemUI() {
       val decorView: View = this.window.decorView
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
           window.setDecorFitsSystemWindows(false)
       } else {
  
            val uiOptions = decorView.systemUiVisibility
            var newUiOptions = uiOptions
            newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_LOW_PROFILE
            newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_FULLSCREEN
            newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_IMMERSIVE
            newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            decorView.systemUiVisibility = newUiOptions
        }
}
    
 private fun showSystemUI() {
        val decorView: View = this.window.decorView
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
          window.setDecorFitsSystemWindows(true)
        } else {
  
            val uiOptions = decorView.systemUiVisibility
            var newUiOptions = uiOptions
            newUiOptions = newUiOptions and View.SYSTEM_UI_FLAG_LOW_PROFILE.inv()
            newUiOptions = newUiOptions and View.SYSTEM_UI_FLAG_FULLSCREEN.inv()
            newUiOptions = newUiOptions and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION.inv()
            newUiOptions = newUiOptions and View.SYSTEM_UI_FLAG_IMMERSIVE.inv()
            newUiOptions = newUiOptions and View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY.inv()
            decorView.systemUiVisibility = newUiOptions
        }
    }

2 Comments

systemUiVisibility is deprecated
@FerozKhan use this instead of systemUiVisibility: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { window.setDecorFitsSystemWindows(false) } else { window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN }
0

Go to https://developer.android.com/training/system-ui/immersive

They had explained this system very properly. And add below style in your activity theme

<style name="BlackActionTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/black</item>
        <item name="colorPrimaryDark">@color/black</item>
        <item name="colorAccent">@color/colorAccent</item>

        <item name="android:windowNoTitle">true</item>
        <item name="android:windowActionBar">false</item>
    </style>

Comments

0

In API version 30 (R) setting window.decorView.systemUiVisibility is deprecated. Use the window.insetsController instead:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    window.insetsController?.let {
        it.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        window.navigationBarColor = getColor(R.color.semi_transparent)
        it.hide(WindowInsets.Type.systemBars())
    }
} else {
    // see other answers
}

For a detailed explanation see https://medium.com/swlh/modifying-system-ui-visibility-in-android-11-e66a4128898b

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.