Reputation: 87
I need your help to understand a strange behavior. When I set the fitsSystemWindows property to 'true', the navigation bar hides some part of my layout, see the image below :
When I set to false, I have this behavior (it's OK) :
When I read the Android documentation and many posts on Stackoverflow, I understand it should be the exact opposite of this behaviour : https://developer.android.com/reference/android/view/View#attr_android:fitsSystemWindows. The first case with fitsSystemWindows='true' should be OK and the second case should be hidden by the navigation bar, am I wrong ?
Could someone explain me what's happened ? My targetVersionSdk is 29 and I tested it on many versions (Android 6,7 10 and 11). Maybe it's specific to CoordinatorLayout ? Thanks for your explanations :)
Here is my xml layout :
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="[true or false]">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</com.google.android.material.appbar.AppBarLayout>
[...]
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_marginBottom="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_vertical_margin"
android:src="@drawable/ic_arrow_forward_white_24dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Upvotes: 2
Views: 3428
Reputation: 581
I think the view is working as expected. First you need to understand the insets and how it's passed around. The default behavior of fitsSystemWindow
is to consume all the insets and apply them as padding. But ViewGroups like CoordinatorLayout, DrawerLayout override this behavior.
Here is the snippet of the code in CoordinatorLayout that overrides the behavior.
private void setupForInsets() {
if (Build.VERSION.SDK_INT < 21) {
return;
}
if (ViewCompat.getFitsSystemWindows(this)) {
if (mApplyWindowInsetsListener == null) {
mApplyWindowInsetsListener =
new androidx.core.view.OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View v,
WindowInsetsCompat insets) {
return setWindowInsets(insets);
}
};
}
ViewCompat.setOnApplyWindowInsetsListener(this, mApplyWindowInsetsListener);
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
} else {
ViewCompat.setOnApplyWindowInsetsListener(this, null);
}
}
As you can see applying fitsSystemWindow
in CoordinatorLayout causes it to render the contents under the system UI. What you need to do is to add the insets provided by the system and apply it as margin or padding to the top and bottom views.
You can use setOnApplyWindowInsetsListener()
to listen for insets and apply it. Let's say you havebottomNav
as bottom view then you can do something like this to account for the bottom inset.
ViewCompat.setOnApplyWindowInsetsListener(bottomNav) { view, insets ->
bottomNav.updatePadding(bottom = insets.systemWindowInsetBottom)
insets
}
You can learn more about insets in this blog post.
Upvotes: 3