WindowInsets??

Andranik Azizbekian
2 min readJan 21, 2017

Have you ever wondered what are WindowInsets used for? Why would you ever need them? You have seen people applying android:fitsSystemWindows=”true” to their layouts but you actually see no difference sometimes? What an API is this? We’ll try to demystify them in this article.

WindowInsets are insets (or sizes) of system views (e.g. status bar, navigation bar), that are applied to the window of your application.

The best way to understand something — is to see it in example. Let’s imagine you have requirement to achieve this UI:

How would I do that?

Well, there is aToolbar and an ImageView in this layout. I’d wrap them in FrameLayout and that’s it, right? Not yet. What I will get there is that theToolbar would be stretched by status bar, i.e. Toolbar will not have necessary top padding in order to be laid out below status bar.

What if I apply android:fitsSystemWindows=”true” to the FrameLayout ?

First, let’s understand what this flag is going to do. When a layout has this flag, it means that this layout is asking the system to be applied window insets. In our case that would mean, that FrameLayout desires to be applied a padding that is equal to status bar’s height.

Well, that’s nice. Is seems like a good idea, that will solve our problem. Actually it won’t, because now the ImageView will also receive this padding, and will be laid out below the status bar.

Luckily, there’s a nice API, that solves our problem — ViewCompat.setOnApplyWindowInsetListener . With this API you can apply window insets to a particular view.

ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, insets) -> {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
params.topMargin = insets.getSystemWindowInsetTop();
return insets.consumeSystemWindowInsets();
});

But insets.getSystemWindowInsetTop() would return 0 in our case, because, remember, we have wrapped our view in FrameLayout .

Standard layouts like FrameLayout , LinearLayout or RelativeLayout will not pass window insets to their children, whereas “materialish” layouts will do (e.g. DrawerLayout , CoordinatorLayout ). So we may change our layout to “materialish” one, or we can subclass a standard layout and pass the insets to the children of layout ourselves. We just have to override onApplyWindowInsets method.

@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; ++index)
getChildAt(index).dispatchApplyWindowInsets(insets);
// let children know about WindowInsets

return insets;
}

That’s it. Now we have the UI we wanted to achieve.

You may also read an article by Ian Lake and a presentation from Chris Banes concerning window insets.

Thanks for reading. Happy droiding! 🤖

--

--

Andranik Azizbekian
Andranik Azizbekian

Written by Andranik Azizbekian

Android enthusiast, Google Certified Android developer, Stackoverflower

Responses (9)