I'm struggling to understand the concept of fitsSystemWindows
as depending on the view it does different things. According to the official documentation it's a
Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows.
Now, checking the View.java
class I can see that when set to true
, the window insets (status bar, navigation bar...) are applied to the view paddings, which works according to the documentation quoted above. This is the relevant part of the code:
private boolean fitSystemWindowsInt(Rect insets) {
if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
Rect localInsets = sThreadLocal.get();
if (localInsets == null) {
localInsets = new Rect();
sThreadLocal.set(localInsets);
}
boolean res = computeFitSystemWindows(insets, localInsets);
mUserPaddingLeftInitial = localInsets.left;
mUserPaddingRightInitial = localInsets.right;
internalSetPadding(localInsets.left, localInsets.top,
localInsets.right, localInsets.bottom);
return res;
}
return false;
}
With the new Material design there are new classes which make extensive use of this flag and this is where the confusion comes. In many sources fitsSystemWindows
is mentioned as the flag to set to lay the view behind the system bars. See here.
The documentation in ViewCompat.java
for setFitsSystemWindows
says:
Sets whether or not this view should account for system screen decorations such as the status bar and inset its content; that is, controlling whether the default implementation of {@link View#fitSystemWindows(Rect)} will be executed. See that method for more details.
According to this, fitsSystemWindows
simply means that the function fitsSystemWindows()
will be executed? The new Material classes seem to just use this for drawing under the status bar. If we look at DrawerLayout.java
's code, we can see this:
if (ViewCompat.getFitsSystemWindows(this)) {
IMPL.configureApplyInsets(this);
mStatusBarBackground = IMPL.getDefaultStatusBarBackground(context);
}
...
public static void configureApplyInsets(View drawerLayout) {
if (drawerLayout instanceof DrawerLayoutImpl) {
drawerLayout.setOnApplyWindowInsetsListener(new InsetsListener());
drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}
And we see the same pattern in the new CoordinatorLayout
or AppBarLayout
.
Doesn't this work in the exact opposite way as the documentation for fitsSystemWindows
? In the last cases, it means draw behind the system bars.
However, if you want a FrameLayout
to draw itself behind the status bar, setting fitsSystemWindows
to true does not do the trick as the default implementation does what's documented initially. You have to override it and add the same flags as the other mentioned classes. Am I missing something?
CoordinatorLayout
, use that flag to infer if they should paint behind the status bar or not. That's not the case withFrameLayout
, for example. – Mourn