Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A fragment container enabling the use of android:fitsSystemWindows in fragment layouts.
package be.digitalia.common.widgets;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.support.v4.util.ObjectsCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowInsets;
import android.widget.FrameLayout;
/**
* A FrameLayout which memorizes the window insets and propagates them to child views before they are measured.
* You can use this layout as a fragment container in place of a standard FrameLayout to
* propagate window insets to attached fragments.
*
* @author Christophe Beyls
*/
public class WindowInsetsFrameLayout extends FrameLayout {
private Object mLastInsets;
public WindowInsetsFrameLayout(Context context) {
super(context);
}
public WindowInsetsFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WindowInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (!ObjectsCompat.equals(mLastInsets, insets)) {
mLastInsets = insets;
requestLayout();
}
return insets.consumeSystemWindowInsets();
}
@SuppressWarnings("deprecation")
@Override
protected boolean fitSystemWindows(Rect insets) {
if (!ObjectsCompat.equals(mLastInsets, insets)) {
if (mLastInsets == null) {
mLastInsets = new Rect(insets);
} else {
((Rect) mLastInsets).set(insets);
}
requestLayout();
}
return true;
}
@SuppressLint("DrawAllocation")
@SuppressWarnings("deprecation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mLastInsets != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
final WindowInsets wi = (WindowInsets) mLastInsets;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
child.dispatchApplyWindowInsets(wi);
}
}
} else {
super.fitSystemWindows(new Rect((Rect) mLastInsets));
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@IlyaEremin

This comment has been minimized.

Copy link

commented Dec 23, 2015

How I can use it? I need to put fragment container inside this view? Or I make root fragment view FitsSystemWindowsFrameLayout

@phamvansy

This comment has been minimized.

Copy link

commented May 15, 2016

How I can use it? I need to put fragment container inside this view? Or I make root fragment view FitsSystemWindowsFrameLayout

<yourpackge.FitsSystemWindowsFrameLayout
...

.
..
</yourpackge.FitsSystemWindowsFrameLayout

@cbeyls

This comment has been minimized.

Copy link
Owner Author

commented Aug 27, 2016

This view itself needs to be used as Fragment container.

@shawnlinboy

This comment has been minimized.

Copy link

commented Nov 18, 2016

Works like magic. THX :)

@onur-ozdemir

This comment has been minimized.

Copy link

commented Apr 16, 2017

thank you. It's work :)

@wzhangmoumou

This comment has been minimized.

Copy link

commented Aug 23, 2017

it doesn't worked for me,but thinks too

@Yazon2006

This comment has been minimized.

Copy link

commented Feb 8, 2018

It seems to me that field private Rect tempInsets = new Rect(); is redundant. Isn't it?

@cbeyls

This comment has been minimized.

Copy link
Owner Author

commented Aug 9, 2018

@Yazon2006 First we need to make a copy of the insets as they arrive, because sibling views may modify them and we need to keep the value as we got it.
Then, when redispatching the insets, the child views may modify them as well and we need to make sure that on the next dispatch, we start with the same value as before. Hence for safety we need to make a second copy of the saved insets before each dispatch.

@cbeyls

This comment has been minimized.

Copy link
Owner Author

commented Aug 9, 2018

I rewrote this class recently, to optimize it for API 20+ while keeping compatibility with older Android versions.
On API 20+ onApplyWindowInsets() will be called. These insets are read-only so we just pass them later as-is to child views without having to do any copy or transformation.
On older versions fitSystemWindows() will be called, and the class makes two defensive copies of the insets to avoid issues if they are modified by other views.
The insets are not passed to child views anymore when they arrive initially, or when a child view is added. Instead they are now dispatched to all child views at once in onMeasure() right before measuring. This behavior is similar to the DrawerLayout implementation.

@afmjoaa

This comment has been minimized.

Copy link

commented Aug 10, 2018

Awesome work Bruh ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.