What are WindowInsets?
You can learn all about WindowInsets here. WindowInsets
provides you with the area on the window that is usable by the application. By itself it's of not much use. It's true purpose comes when you either override View.onApplyWindowInsets
or implement View.OnApplyWindowInsetsListener
. You can read about them here: View.onApplyWindowInsets and View.OnApplyWindowInsetsListener.
Listener for applying window insets on a view in a custom way.
Apps may choose to implement this interface if they want to apply
custom policy to the way that window insets are treated for a view. If
an OnApplyWindowInsetsListener is set, its onApplyWindowInsets method
will be called instead of the View's own onApplyWindowInsets method.
The listener may optionally call the parameter View's
onApplyWindowInsets method to apply the View's normal behavior as part
of its own.
In short, overriding this will let you control area of the window available for your View.
In Android, what are window insets?
They are some kind of colored margin (used in Android Wear).
They are used to create a padding from the main content to the actual border:
There are a few examples here.
This is an image with 2 insets: Circle/Squared.
They can also be used in other views to handle especial rendering requirements, like in a ScrollView: where to put the actual scroll can be defined with an insideInset as mentioned in this question.
<ScrollView
android:id="@+id/view2"
android:layout_width="100dip"
android:layout_height="120dip"
android:padding="8dip"
android:scrollbarStyle="insideInset"
android:background="@android:color/white"
android:overScrollMode="never">
How many WindowInsets are there?
WindowInsets describes a set of insets for window content.
In other words, WindowInsets
has one rect of the available area for the app (and has other info like isRound
). Available area excludes the rect of StatusBar
and NavigationBar
.
If you just want to know the height of StatusBar
and NavigationBar
, check this.
You can get WindowInsets
like following.
Following example uses WindowInsetsCompat for compatibility.
In your style.xml:
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
...
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
In your AndroidManifest.xml
<application
...
android:theme="@style/AppTheme">
...
</application>
In your layout xml: (fitsSystemWindows should be set to get WindowInsets.)
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
In your Activity (or any place):
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View container = findViewById(R.id.container);
ViewCompat.setOnApplyWindowInsetsListener(container, new OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
//you can do something with insets.
int statusBar = insets.getSystemWindowInsetTop(); //this is height of statusbar
int navigationBar = insets.getStableInsetBottom(); //this is height of navigationbar
Log.d("MainActivity", String.format("%s %s", statusBar, navigationBar));
ViewCompat.onApplyWindowInsets(v, insets);
return insets;
}
});
}
}
WindowInsets is like this:
Show keyboard over Scaffold's bottomBar in Jetpack Compose and apply proper inset paddings
According to Accompanist Insets migration, LocalWindowInsets.current.ime
should be replaced with WindowInsets.ime
.
It doesn't have isVisible
for now, until this bug is fixed. Here's how I've re-created it for now:
val WindowInsets.Companion.isImeVisible: Boolean
@Composable
get() {
val density = LocalDensity.current
val ime = this.ime
return remember {
derivedStateOf {
ime.getBottom(density) > 0
}
}.value
}
Usage:
val isImeVisible = WindowInsets.isImeVisible
This should work with your old remember(isImeVisible)
code.
Go edge-to-edge on Android correctly with WindowInsets
Edit 2022-01-16:
Nowadays we can use https://google.github.io/accompanist/insets to get insets for jetpack compose and just add WindowCompat.setDecorFitsSystemWindows(window, false)
like @shogun-nassar points out correctly in his answer.
Original answer:
To provide a final answer:
Do not use android:fitsSystemWindows
anywhere but apply insets manually to any view at the edge of the screen which would otherwise slip behind the system bars (e.g. AppBarLayout
or FloatingActionButton
).
I wrote some helpers to add the insets to either padding or margin, respecting any previously added one (needs androidx.core:core:1.2.0-alpha01):
fun View.addSystemWindowInsetToPadding(
left: Boolean = false,
top: Boolean = false,
right: Boolean = false,
bottom: Boolean = false
) {
val (initialLeft, initialTop, initialRight, initialBottom) =
listOf(paddingLeft, paddingTop, paddingRight, paddingBottom)
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
view.updatePadding(
left = initialLeft + (if (left) insets.systemWindowInsetLeft else 0),
top = initialTop + (if (top) insets.systemWindowInsetTop else 0),
right = initialRight + (if (right) insets.systemWindowInsetRight else 0),
bottom = initialBottom + (if (bottom) insets.systemWindowInsetBottom else 0)
)
insets
}
}
fun View.addSystemWindowInsetToMargin(
left: Boolean = false,
top: Boolean = false,
right: Boolean = false,
bottom: Boolean = false
) {
val (initialLeft, initialTop, initialRight, initialBottom) =
listOf(marginLeft, marginTop, marginRight, marginBottom)
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
view.updateLayoutParams {
(this as? ViewGroup.MarginLayoutParams)?.let {
updateMargins(
left = initialLeft + (if (left) insets.systemWindowInsetLeft else 0),
top = initialTop + (if (top) insets.systemWindowInsetTop else 0),
right = initialRight + (if (right) insets.systemWindowInsetRight else 0),
bottom = initialBottom + (if (bottom) insets.systemWindowInsetBottom else 0)
)
}
}
insets
}
}
As an example, simply call fab.addSystemWindowInsetToMargin(bottom = true)
and the FAB will be moved up above the navigation bar. Or app_bar.addSystemWindowInsetToPadding(top = true)
to keep the app bar below the status bar (mind the margin/padding difference).
What are insets in android?
Suppose you have a TextView and you need to add a background to the TextView. But, on the other hand, you don't want the background to scan the entire View (TextView), therefore, you need to use Insets.
A Drawable that insets another Drawable by a specified distance or
fraction of the content bounds. This is used when a View needs a
background that is smaller than the View's actual bounds.
The background can be a Drawable. Hence you need to use the <inset>
attribute inside your xml file (activity_main.xml) "For Example".
Then, after using the <inset>
tag, you can specify some attributes such as:
<inset
android:drawable="@drawable/(Enter the file name under drawable)"
android:insetBottom="4dp"
android:insetTop="4dp"/>
For more information please have a look at InsetDrawable on Android developer.com
Hope this helps!
onApplyWindowInsets(WindowInsets insets) not getting called
Once the insets are consumed, propagation down the hierarchy stops. It looks like something higher up is consuming what's available. See isConsumed()
of WindowsInset.
Check if these insets have been fully consumed.
Insets are considered "consumed" if the applicable consume* methods have been called such that all insets have been set to zero. This affects propagation of insets through the view hierarchy; insets that have not been fully consumed will continue to propagate down to child views.
Related Topics
Android Studio Convert Iso String to "America/New_York" When Adding to Event to Calendar
How to Automatically Generate Getters and Setters in Eclipse
Using Client/Server Certificates for Two Way Authentication Ssl Socket on Android
Check for Active Internet Connection Android
How to Implement a Fileobserver from an Android Service
How to Send Data from Dialogfragment to a Fragment
How to Catch a Firebase Auth Specific Exceptions
Android: Textview Automatically Truncate and Replace Last 3 Char of String
How to Hash a String in Android
Change Icons of Checked and Unchecked for Checkbox for Android
Android Days Between Two Dates
Passing a JavaScript Object Using Addjavascriptinterface() on Android