android:fitsSystemWindows="true" has issues with using DrawerLayout and immersive mode
Asked Answered
F

2

6

I'm having issues when trying to use immersive mode and using android:fitsSystemWindows="true" with DrawerLayout. I have to set this to true for the DrawerLayout and toolbar to be constrained to the system bar.

The issue is, I have a Fragment which sets the application to immersive mode. This makes the app do this: Fullscreen with system bars

Which I know is a known issue with android:fitsSystemWindows="true". I set it to false and immersive mode works well but the toolbar and the rest of the layout is no longer constrained to the system bars. I try setting the value at runtime and the lower portion of the layout (aka the navigation bar area) is filled by my layout, but the system bar area is still showing: Fullscreen with status bar

Here is my code:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">

<include
    layout="@layout/app_bar_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<android.support.design.widget.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/nav_header_main"
    app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>

ClockFragment.java - Hide and Show

private void hideSystemUI() {
    if (Build.VERSION.SDK_INT >= 14) {
        getActivity().findViewById(R.id.drawer_layout).setFitsSystemWindows(false);
    }
    getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    if (Build.VERSION.SDK_INT >= 19) {
        mDecorView.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);
    } else if (Build.VERSION.SDK_INT >= 16) {
        mDecorView.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);
    } else {
        getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
    toolbar.setVisibility(View.GONE);
    layoutParams.screenBrightness = -1.00f;
    getActivity().getWindow().setAttributes(layoutParams);
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
    uiShowing = false;
    dimming = false;
    screenMode = 1;
}

private void hideSystemUIAndDim() {
    if (Build.VERSION.SDK_INT >= 14) {
        getActivity().findViewById(R.id.drawer_layout).setFitsSystemWindows(false);
    }
    getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    if (Build.VERSION.SDK_INT >= 19) {
        mDecorView.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);
    } else if (Build.VERSION.SDK_INT >= 16) {
        mDecorView.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);
    } else {
        getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
    toolbar.setVisibility(View.GONE);
    layoutParams.screenBrightness = 0.01f;
    getActivity().getWindow().setAttributes(layoutParams);
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
    uiShowing = false;
    dimming = true;
    screenMode = 2;
}

private void showSystemUI() {
    if (Build.VERSION.SDK_INT >= 14) {
        getActivity().findViewById(R.id.drawer_layout).setFitsSystemWindows(true);
    }
    if (Build.VERSION.SDK_INT >= 16) {
        mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    } else {
        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    }
    toolbar.setVisibility(View.VISIBLE);
    layoutParams.screenBrightness = -1.00f;
    getActivity().getWindow().setAttributes(layoutParams);
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
    uiShowing = true;
    dimming = false;
    screenMode = 0;
}
Fogel answered 25/3, 2016 at 19:44 Comment(0)
F
10

OK I finally fixed my problem. Turns out that I needed to add the FLAG_FULLSCREEN flag. Here is my fixed code for future viewers:

private void hideSystemUI() {
    if (Build.VERSION.SDK_INT >= 14) {
        drawerLayout.setFitsSystemWindows(false);
    }
    getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    if (Build.VERSION.SDK_INT >= 19) {
        mDecorView.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);
    } else if (Build.VERSION.SDK_INT >= 16) {
        mDecorView.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);
    }
    toolbar.setVisibility(View.GONE);
    layoutParams.screenBrightness = -1.00f;
    getActivity().getWindow().setAttributes(layoutParams);
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
    uiShowing = false;
    dimming = false;
    screenMode = 1;
}

private void hideSystemUIAndDim() {
    if (Build.VERSION.SDK_INT >= 14) {
        drawerLayout.setFitsSystemWindows(false);
    }
    getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    if (Build.VERSION.SDK_INT >= 19) {
        mDecorView.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);
    } else if (Build.VERSION.SDK_INT >= 16) {
        mDecorView.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);
    }
    toolbar.setVisibility(View.GONE);
    layoutParams.screenBrightness = 0.01f;
    getActivity().getWindow().setAttributes(layoutParams);
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
    uiShowing = false;
    dimming = true;
    screenMode = 2;
}

private void showSystemUI() {
    try {
        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        if (Build.VERSION.SDK_INT >= 14) {
            drawerLayout.setFitsSystemWindows(true);
        }
        if (Build.VERSION.SDK_INT >= 16) {
            mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
        toolbar.setVisibility(View.VISIBLE);
        layoutParams.screenBrightness = -1.00f;
        getActivity().getWindow().setAttributes(layoutParams);
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        uiShowing = true;
        dimming = false;
        screenMode = 0;
    } catch (NullPointerException e) {
        Log.e(TAG, e.toString());
    }
}
Fogel answered 26/3, 2016 at 23:29 Comment(1)
This is the most relevant answer to this problem. However, I found that in my case the first child of the drawer layout did not automatically adjust its margin/insets (it's layout parameters also weren't regular layout parameters, but DrawerLayout parameters). I could only solve it by calling setMargins(0, 0, 0, 0); on its layout parameters. If anyone else faces this problem, and has a more elegant solution I'd be happy to learn from you!Apathy
P
2

I thought I would add the following code to the conversation. I needed to switch between normal viewing and fullscreen and kept having various layout difficulties. This was caused because DrawerLayout processes setFitsSystemWindows() in a non-standard way. The following code accomplished what I needed.

The first secret was to modify setFitsSystemWindows() on the CoordinatorLayout instead of the DrawerLayout in the XML file:

<android.support.v4.widget.DrawerLayout
android:id="@+id/drawerlayout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent" >

    <!-- android:fitsSystemWindows="true" moves rootCoordinatorLayout below the system status bar.
        When it is specified the theme should include <item name="android:windowTranslucentStatus">true</item>. -->
    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinatorlayout"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:fitsSystemWindows="true" >

        <!-- Include other layouts specific to the app. -->

    </android.support.design.widget.CoordinatorLayout>

    <!-- The navigation drawer. -->
    <android.support.design.widget.NavigationView
        android:id="@+id/navigationview"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="start"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/navigation_menu" />
</android.support.v4.widget.DrawerLayout>

The theme should specify <item name="android:windowTranslucentStatus">true</item> in styles.xml.

<resources>
    <!-- `android:windowTranslucentStatus` makes the system status bar translucent.
        When it is specified the root layout should include android:fitsSystemWindows="true". -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">true</item>
    </style>
</resources>

In Java, get handles for both the DrawerLayout and the CoordinatorLayout.

DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawerlayout);
CoordinatorLayout coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorlayout);

This app has a SupportActionBar. We need a handle for it so it can be hidden and revealed.

supportActionBar = getSupportActionBar();

To toggle the status and navigation bars as translucent overlays, use the following code:

if (supportActionBar.isShowing()) {  // If `supportActionBar` is visible, switch to full screen mode.
    // Hide `supportActionBar`.
    supportActionBar.hide();

    // Set `coordinatorLayout` to fit under the status and navigation bars.
    coordinatorLayout.setFitsSystemWindows(false);

    // Set the navigation bar to be translucent.
    // There is an Android Support Library bug that causes a scrim to print on the right side of the `Drawer Layout` when the navigation bar is displayed on the right of the screen.
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
} else {  // Switch to normal viewing mode.
    // Show `supportActionBar`.
    supportActionBar.show();

    // Constrain `coordinatorLayout` inside the status and navigation bars.
    coordinatorLayout.setFitsSystemWindows(true);

    // Remove the translucent navigation bar flag.
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}

Alternately, to toggle completely hiding the status and navigation bars in immersive mode, use the following code.

if (supportActionBar.isShowing()) {  // If `supportActionBar` is visible, switch to full screen mode.
    // Hide `supportActionBar`.
    supportActionBar.hide();

    // Remove the translucent overlays.
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    // Remove the translucent status bar overlay on the `Drawer Layout`, which is special and needs its own command.
    drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

    /* SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
     * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
     * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically rehides them after they are shown.
     */
    coordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

    // Set `coordinatorLayout` to fill the whole screen.
    CoordinatorLayout.setFitsSystemWindows(false);
} else {  // Switch to normal viewing mode.
    // Show `supportActionBar`.
    supportActionBar.show();

    // Add the translucent status flag if it is unset.  This also resets `drawerLayout's` `View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN`.
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    // Remove the `SYSTEM_UI` flags from `coordinatorLayout`.
    coordinatorLayout.setSystemUiVisibility(0);

    // Constrain `coordinatorLayout` inside the status and navigation bars.
    coordinatorLayout.setFitsSystemWindows(true);
}
Perfunctory answered 24/11, 2016 at 18:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.