CoordinatorLayout children are not fullscreen

2019-03-29 08:24发布

I have an Activity which is displayed fullscreen. This works perfectly with many layouts I have tried, except for when the CoordinatorLayout is the root ViewGroup. The CoordinatorLayout itself has both width and height set to match_parent and it takes the whole screen as it should. But the child views that should have the same size as the CoordinatorLayout are laid as if the navigation bar was still visible.

Illustration of the problem

Is there a way to make the child views resize with the CoordinatorLayout? Obviously fitSystemWindows does not change a thing as this is probably caused by the CoordinatorLayout implementation, other ViewGroups work well. I have tried to create custom Behavior class but I was not successful with that.

I use this code to make my Activity fullscreen:

@Override
protected void onResume() {
    super.onResume();
    int uiOptions = 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;
    getWindow().getDecorView().setSystemUiVisibility(uiOptions);
}

This is a simple layout used to generate the image:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:background="#F00">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:scaleType="centerCrop"
        android:src="@drawable/background_sky_light" />

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

3条回答
ゆ 、 Hurt°
2楼-- · 2019-03-29 08:49

You may try removing android:fitsSystemWindows="true" from ImageView, and change onResume() like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    ....
    mRootView = (CoordinatorLayout) findViewById(R.id.coordinatorLayout);
    ....
}

public void hideBars() {
    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    mRootView.setFitsSystemWindows(false);
}

The mRootView.setFitsSystemWindows(false); is important for fitting child views into full screen.

Without this call, the layout would appear as if the status bar and navigation bar still exists. As shown in the picture below:

Screenshot without setFitsSystemWindows(false)

And with this call:

Screenshot with setFitsSystemWindows(false)

The reason, I think, is that when fitsSystemWindows is true, the CoordinatorLayout will reserve space for status bar and navigation bar in order to work with other widgets which draw background of bars themselves. But when we hide the System UI bars, there is no need to reserve space, and thus we need to tell CoordinatorLayout to release the spaces for other child views.

Following is the layouts in the screenshot

Layout for the activity:

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/coordinatorLayout"
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:fitsSystemWindows="true"
    tools:context="org.hamster.carz.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

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

    <include layout="@layout/frag_container"/>
    <!-- Just a empty FrameLayout -->

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@mipmap/car_add" />

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

The fragment in the screenshots above:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:orientation="vertical">

        <Button
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginBottom="2dp"
            android:layout_weight="1"
            android:background="@drawable/controller_button"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginTop="2dp"
            android:layout_weight="1"
            android:background="@drawable/controller_button"/>
    </LinearLayout>

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:layout_weight="1">

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab_disconnect"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_margin="@dimen/fab_margin"
            android:src="@mipmap/ic_clear"
            app:backgroundTint="@color/colorAccentDark"/>
    </FrameLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:orientation="vertical">

        <Button
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginBottom="2dp"
            android:layout_weight="1"
            android:background="@drawable/controller_button"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginTop="2dp"
            android:layout_weight="1"
            android:background="@drawable/controller_button"/>
    </LinearLayout>

</LinearLayout>

Hope this helps.

查看更多
地球回转人心会变
3楼-- · 2019-03-29 08:52

I had a similar issue and had to hack a bit of a solution. Instead of an ImageView, my CoordinatorLayout child view is for streaming a video. Since I am streaming a video during rotation, I need to to watch for configChanges and override onConfigurationChanged. This may not work for you if you do not want to override onConfigurationChanged, but it may work out. Like I said, it's a bit of a hack, but works for me.

I end up fully expanding the Toolbar, storing the offset, then hiding it (treating it as a standard view). Then when I rotate back, I am resizing it to whatever the offset was when the user rotated the device.

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        showToolbar();
        mViewPager.setVisibility(View.VISIBLE);

    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        hideToolbar();
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        mViewPager.setVisibility(View.GONE);
    }
}

public void hideToolbar()
{
    setCurrentOffset();
    expandToolbarToHeight(0);
    findViewById(R.id.toolbar).setVisibility(View.GONE);
}

public void showToolbar()
{
    expandToolbarToHeight(oldOffset);
    findViewById(R.id.toolbar).setVisibility(View.VISIBLE);
}

public void setCurrentOffset() {
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
    AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
    if (behavior != null) {
        oldOffset = behavior.getTopAndBottomOffset();
    }
}

public void expandToolbarToHeight(int height) {
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
    AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
    if (behavior != null) {
        behavior.setTopAndBottomOffset(height);
        behavior.onNestedPreScroll(mCoordinatorLayout, mAppBarLayout, null, 0, 1, new int[2]);
    }
}
查看更多
叛逆
4楼-- · 2019-03-29 08:57

change android:fitsSystemWindows to false if you are using coodinatorlayout android:fitsSystemWindows="false"

查看更多
登录 后发表回答