System windows are the parts of the screen where the system is drawing either non-interactive (in the case of the status bar) or interactive (in the case of the navigation bar) content.
Most of the time, your app won’t need to draw under the status bar or the navigation bar, but if you do: you need to make sure interactive elements (like buttons) aren’t hidden underneath them. That’s what the default behavior of the
android:fitsSystemWindows="true" attribute gives you: it sets the padding of the View to ensure the contents don’t overlay the system windows.
A few things to keep in mind:
fitsSystemWindowsis applied depth first — ordering matters: it’s the first View that consumes the insets that makes a difference
- Insets are always relative to the full window — insets may be applied even before layout happens, so don’t assume the default behavior knows anything about the position of a View when applying its padding
- Any other padding you’ve set is overwritten — you’ll note that
paddingTop/etc is ineffective if you are using
android:fitsSystemWindows="true"on the same View
And, in many cases, such as a full screen video playback, that’s enough. You’d have your full bleed view with no attribute and another full screen
android:fitsSystemWindows="true" for your controls that you want inset.
Or maybe you want your
RecyclerView to scroll underneath a transparent navigation bar — by using
android:fitsSystemWindows="true" in conjunction with
android:clipToPadding="false", your scrolling content will be behind the controls but, when scrolled to the bottom, the last item will still be padded to be above the navigation bar (rather than hidden underneath!).
But this default behavior is just that: a default. On KitKat and below, your custom View could override
fitSystemWindows() and provide any functionality you wanted — just return
true if you’ve consumed the insets or false if you’d like to give other Views a chance.
However, on Lollipop and higher devices, we provide some new APIs to make customizing this behavior much easier and consistent with other behaviors for Views. You’ll instead override
onApplyWindowInsets(), which allows the View to consume as much or as little of the insets as you need and be able to call
dispatchApplyWindowInsets() on child views as needed.
Even better, you don’t even need to subclass your Views if you only need custom behavior on Lollipop and higher — you can use
ViewCompat.setOnApplyWindowInsetsListener(), which will be given preference over the View’s
ViewCompat also provides helper methods for calling
dispatchApplyWindowInsets() without version checking.
Examples of customizing fitsSystemWindows
While the basic layouts (
LinearLayout, etc) use the default behavior, there are a number of layouts that already customize how they react to
fitsSystemWindows to fit specific use cases.
One example is the navigation drawer which needs to span the whole screen and appear under a transparent status bar.
fitsSystemWindows as a sign that it needs to inset its children (such as the main content view — just like the default behavior), but still draw the status bar background (which defaults to your theme’s
colorPrimaryDark) in that space as per the material design specs.
dispatchApplyWindowInsets() for each child on Lollipop and higher to allow child views to also receive
fitsSystemWindows, a departure from the default (where normally it would simply consume the insets and children would never receive
CoordinatorLayout also takes advantage of overriding how it handles window insets, allowing the
Behavior set on child Views to intercept and change how Views react to window insets, before calling
dispatchApplyWindowInsets() on each child themselves. It also uses the
fitsSystemWindows flag to know if it needs to paint the status bar background.
CollapsingToolbarLayout looks for
fitsSystemWindows to determine when and where to draw the content scrim — a full-bleed scrim which overlays the status bar area when the
CollapsingToolbarLayout is scrolled sufficiently off the screen.
Use the system, don’t fight it
One thing to keep in mind is that it isn’t called
fitsNavigationBar. What constitutes system windows, their dimensions, and location may certainly change with different platform releases — for a perfect example, look at the differences between Honeycomb and Ice Cream Sandwich.
Just rest assured that the insets you do get from
fitsSystemWindows will be correct on all platform versions to ensure your content does not overlap with system provided UI components — make sure to avoid any assumptions on their availability or size if you customize the behavior.