OnApplyWindowInsetsListener gives systemWindowInsetBottom that is always 0
systemWindowInsetBottom AND stableInsetBottom are both always 0
I have an Activity, that has a background texture, and I am using FLAG_LAYOUT_NO_LIMITS to let that background go behind the status and navigation bar. But I don't want the other contents of the view to go behind those system UI components.
At first I thought of using resources.getIdentifier("navigation_bar_height", "dimen", "android")
to get the height of the navigation bar, but that's just the default height of the navigation bar, so it won't work on devices where the user has hidden the navigation bar. (Samsung devices)
Then I found out about WindowInsets and android:fitsSystemWindows="true"
It works for the status bar, but it does not work for the navigation bar.
In my Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//These 2 flags don't seem to change anything
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR)
//This flag is required so the background can go behind the navbar
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.setOnApplyWindowInsetsListener { _, insets ->
val topTextViewParams = rootView.tvTop.layoutParams as ViewGroup.MarginLayoutParams
topTextViewParams.topMargin = insets.systemWindowInsetTop
val bottomTextViewParams = rootView.tvBottom.layoutParams as ViewGroup.MarginLayoutParams
bottomTextViewParams.bottomMargin = insets.systemWindowInsetBottom //Inset is always 0
insets.consumeSystemWindowInsets()
}
}
And my layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:id="@+id/rootView"
android:background="@color/colorPrimary"
tools:context=".MainActivity">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="Text aligned to bottom of layout with no margin"/>
<TextView
android:id="@+id/tvTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="Text aligned to top of layout with no margin"/>
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
Example screenshots from Nexus 5x Emulator running API 28. Getting same results on my actual device running API 26.
What do I have to do to get the actual size of the navigation bar, if it is present?
android
add a comment |
systemWindowInsetBottom AND stableInsetBottom are both always 0
I have an Activity, that has a background texture, and I am using FLAG_LAYOUT_NO_LIMITS to let that background go behind the status and navigation bar. But I don't want the other contents of the view to go behind those system UI components.
At first I thought of using resources.getIdentifier("navigation_bar_height", "dimen", "android")
to get the height of the navigation bar, but that's just the default height of the navigation bar, so it won't work on devices where the user has hidden the navigation bar. (Samsung devices)
Then I found out about WindowInsets and android:fitsSystemWindows="true"
It works for the status bar, but it does not work for the navigation bar.
In my Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//These 2 flags don't seem to change anything
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR)
//This flag is required so the background can go behind the navbar
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.setOnApplyWindowInsetsListener { _, insets ->
val topTextViewParams = rootView.tvTop.layoutParams as ViewGroup.MarginLayoutParams
topTextViewParams.topMargin = insets.systemWindowInsetTop
val bottomTextViewParams = rootView.tvBottom.layoutParams as ViewGroup.MarginLayoutParams
bottomTextViewParams.bottomMargin = insets.systemWindowInsetBottom //Inset is always 0
insets.consumeSystemWindowInsets()
}
}
And my layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:id="@+id/rootView"
android:background="@color/colorPrimary"
tools:context=".MainActivity">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="Text aligned to bottom of layout with no margin"/>
<TextView
android:id="@+id/tvTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="Text aligned to top of layout with no margin"/>
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
Example screenshots from Nexus 5x Emulator running API 28. Getting same results on my actual device running API 26.
What do I have to do to get the actual size of the navigation bar, if it is present?
android
add a comment |
systemWindowInsetBottom AND stableInsetBottom are both always 0
I have an Activity, that has a background texture, and I am using FLAG_LAYOUT_NO_LIMITS to let that background go behind the status and navigation bar. But I don't want the other contents of the view to go behind those system UI components.
At first I thought of using resources.getIdentifier("navigation_bar_height", "dimen", "android")
to get the height of the navigation bar, but that's just the default height of the navigation bar, so it won't work on devices where the user has hidden the navigation bar. (Samsung devices)
Then I found out about WindowInsets and android:fitsSystemWindows="true"
It works for the status bar, but it does not work for the navigation bar.
In my Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//These 2 flags don't seem to change anything
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR)
//This flag is required so the background can go behind the navbar
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.setOnApplyWindowInsetsListener { _, insets ->
val topTextViewParams = rootView.tvTop.layoutParams as ViewGroup.MarginLayoutParams
topTextViewParams.topMargin = insets.systemWindowInsetTop
val bottomTextViewParams = rootView.tvBottom.layoutParams as ViewGroup.MarginLayoutParams
bottomTextViewParams.bottomMargin = insets.systemWindowInsetBottom //Inset is always 0
insets.consumeSystemWindowInsets()
}
}
And my layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:id="@+id/rootView"
android:background="@color/colorPrimary"
tools:context=".MainActivity">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="Text aligned to bottom of layout with no margin"/>
<TextView
android:id="@+id/tvTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="Text aligned to top of layout with no margin"/>
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
Example screenshots from Nexus 5x Emulator running API 28. Getting same results on my actual device running API 26.
What do I have to do to get the actual size of the navigation bar, if it is present?
android
systemWindowInsetBottom AND stableInsetBottom are both always 0
I have an Activity, that has a background texture, and I am using FLAG_LAYOUT_NO_LIMITS to let that background go behind the status and navigation bar. But I don't want the other contents of the view to go behind those system UI components.
At first I thought of using resources.getIdentifier("navigation_bar_height", "dimen", "android")
to get the height of the navigation bar, but that's just the default height of the navigation bar, so it won't work on devices where the user has hidden the navigation bar. (Samsung devices)
Then I found out about WindowInsets and android:fitsSystemWindows="true"
It works for the status bar, but it does not work for the navigation bar.
In my Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//These 2 flags don't seem to change anything
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR)
//This flag is required so the background can go behind the navbar
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.setOnApplyWindowInsetsListener { _, insets ->
val topTextViewParams = rootView.tvTop.layoutParams as ViewGroup.MarginLayoutParams
topTextViewParams.topMargin = insets.systemWindowInsetTop
val bottomTextViewParams = rootView.tvBottom.layoutParams as ViewGroup.MarginLayoutParams
bottomTextViewParams.bottomMargin = insets.systemWindowInsetBottom //Inset is always 0
insets.consumeSystemWindowInsets()
}
}
And my layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:id="@+id/rootView"
android:background="@color/colorPrimary"
tools:context=".MainActivity">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="Text aligned to bottom of layout with no margin"/>
<TextView
android:id="@+id/tvTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="Text aligned to top of layout with no margin"/>
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
Example screenshots from Nexus 5x Emulator running API 28. Getting same results on my actual device running API 26.
What do I have to do to get the actual size of the navigation bar, if it is present?
android
android
asked Nov 25 '18 at 16:42
lbenedettolbenedetto
579316
579316
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
I spend like 3 hours researching this before I posted and then 5 minutes after I posted.
Those 5 minutes were very fruitful, because I found this post, which led me to try adding:
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
To my AppTheme, which worked.
So, if you're trying to do this, make sure you:
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
val childCount = childCount
for (index in 0 until childCount)
getChildAt(index).dispatchApplyWindowInsets(insets)
// let children know about WindowInsets
return insets
}
OR
Use a "materialish layout such as DrawerLayout or CoordinatorLayout" like I did in my post.
Make sure to use android:fitsSystemWindows="true"
Make sure to add those properties to your theme.
And finally make to do something in your setOnApplyWindowInsetsListener
add a comment |
Here's what I had to do to get both completely transparent status bar and navigation bar, with insets applied:
My root view is a ContstraintLayout
. Somehow it's working even without fitsSystemWindows
and I'm getting the insets for both the top and bottom, which I've applied to my Toolbar
and FrameLayout
margins.
In the theme:
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
setImmersive
function in Activity
:
I've created this function to apply the insets and window flags required to achieve the immersive look for a layout which can have:
- Root view
- Top view
- Content
- Bottom view
/**
* Apply immersive mode to this activity
* @param rootView the root layout which will receive the window insets
* @param topView the top view to apply insets to (optional)
* @param bottomView the bottom view to apply insets to (optional)
*/
fun setImmersive(rootView: ViewGroup, topView: View? = null, bottomView: View? = null) {
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
bottomView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
rootView.setOnApplyWindowInsetsListener { _, insets ->
Log.d(javaClass.simpleName + " windowInsets", insets.toString())
// Apply the top insets
if (topView != null) {
insets.systemWindowInsetTop.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetTop $this")
val layoutParams = topView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = this
topView.layoutParams = layoutParams
}
}
}
// Apply the bottom insets
if (bottomView != null) {
insets.systemWindowInsetBottom.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetBottom $this")
val layoutParams = bottomView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.bottomMargin = this
bottomView.layoutParams = layoutParams
}
}
}
insets.consumeSystemWindowInsets()
}
}
Call this function in your onCreate
eg.:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.brand_activity)
setImmersive(root_view, topView = toolbar, bottomView = root_content)
}
The OnApplyWindowInsetsListener
on the root view was getting called twice, once with the correct insets WindowInsets{systemWindowInsets=Rect(0, 98 - 0, 168)
and again with 0 insets WindowInsets{systemWindowInsets=Rect(0, 0 - 0, 0)
. So I'm only setting margins on the non-zero insets.
In the layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_view">
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:id="@+id/root_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar_layout"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/toolbar_title"
android:textStyle="bold"
android:layout_gravity="center" />
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53469643%2fonapplywindowinsetslistener-gives-systemwindowinsetbottom-that-is-always-0%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
I spend like 3 hours researching this before I posted and then 5 minutes after I posted.
Those 5 minutes were very fruitful, because I found this post, which led me to try adding:
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
To my AppTheme, which worked.
So, if you're trying to do this, make sure you:
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
val childCount = childCount
for (index in 0 until childCount)
getChildAt(index).dispatchApplyWindowInsets(insets)
// let children know about WindowInsets
return insets
}
OR
Use a "materialish layout such as DrawerLayout or CoordinatorLayout" like I did in my post.
Make sure to use android:fitsSystemWindows="true"
Make sure to add those properties to your theme.
And finally make to do something in your setOnApplyWindowInsetsListener
add a comment |
I spend like 3 hours researching this before I posted and then 5 minutes after I posted.
Those 5 minutes were very fruitful, because I found this post, which led me to try adding:
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
To my AppTheme, which worked.
So, if you're trying to do this, make sure you:
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
val childCount = childCount
for (index in 0 until childCount)
getChildAt(index).dispatchApplyWindowInsets(insets)
// let children know about WindowInsets
return insets
}
OR
Use a "materialish layout such as DrawerLayout or CoordinatorLayout" like I did in my post.
Make sure to use android:fitsSystemWindows="true"
Make sure to add those properties to your theme.
And finally make to do something in your setOnApplyWindowInsetsListener
add a comment |
I spend like 3 hours researching this before I posted and then 5 minutes after I posted.
Those 5 minutes were very fruitful, because I found this post, which led me to try adding:
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
To my AppTheme, which worked.
So, if you're trying to do this, make sure you:
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
val childCount = childCount
for (index in 0 until childCount)
getChildAt(index).dispatchApplyWindowInsets(insets)
// let children know about WindowInsets
return insets
}
OR
Use a "materialish layout such as DrawerLayout or CoordinatorLayout" like I did in my post.
Make sure to use android:fitsSystemWindows="true"
Make sure to add those properties to your theme.
And finally make to do something in your setOnApplyWindowInsetsListener
I spend like 3 hours researching this before I posted and then 5 minutes after I posted.
Those 5 minutes were very fruitful, because I found this post, which led me to try adding:
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
To my AppTheme, which worked.
So, if you're trying to do this, make sure you:
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
val childCount = childCount
for (index in 0 until childCount)
getChildAt(index).dispatchApplyWindowInsets(insets)
// let children know about WindowInsets
return insets
}
OR
Use a "materialish layout such as DrawerLayout or CoordinatorLayout" like I did in my post.
Make sure to use android:fitsSystemWindows="true"
Make sure to add those properties to your theme.
And finally make to do something in your setOnApplyWindowInsetsListener
answered Nov 25 '18 at 16:54
lbenedettolbenedetto
579316
579316
add a comment |
add a comment |
Here's what I had to do to get both completely transparent status bar and navigation bar, with insets applied:
My root view is a ContstraintLayout
. Somehow it's working even without fitsSystemWindows
and I'm getting the insets for both the top and bottom, which I've applied to my Toolbar
and FrameLayout
margins.
In the theme:
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
setImmersive
function in Activity
:
I've created this function to apply the insets and window flags required to achieve the immersive look for a layout which can have:
- Root view
- Top view
- Content
- Bottom view
/**
* Apply immersive mode to this activity
* @param rootView the root layout which will receive the window insets
* @param topView the top view to apply insets to (optional)
* @param bottomView the bottom view to apply insets to (optional)
*/
fun setImmersive(rootView: ViewGroup, topView: View? = null, bottomView: View? = null) {
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
bottomView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
rootView.setOnApplyWindowInsetsListener { _, insets ->
Log.d(javaClass.simpleName + " windowInsets", insets.toString())
// Apply the top insets
if (topView != null) {
insets.systemWindowInsetTop.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetTop $this")
val layoutParams = topView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = this
topView.layoutParams = layoutParams
}
}
}
// Apply the bottom insets
if (bottomView != null) {
insets.systemWindowInsetBottom.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetBottom $this")
val layoutParams = bottomView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.bottomMargin = this
bottomView.layoutParams = layoutParams
}
}
}
insets.consumeSystemWindowInsets()
}
}
Call this function in your onCreate
eg.:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.brand_activity)
setImmersive(root_view, topView = toolbar, bottomView = root_content)
}
The OnApplyWindowInsetsListener
on the root view was getting called twice, once with the correct insets WindowInsets{systemWindowInsets=Rect(0, 98 - 0, 168)
and again with 0 insets WindowInsets{systemWindowInsets=Rect(0, 0 - 0, 0)
. So I'm only setting margins on the non-zero insets.
In the layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_view">
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:id="@+id/root_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar_layout"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/toolbar_title"
android:textStyle="bold"
android:layout_gravity="center" />
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
add a comment |
Here's what I had to do to get both completely transparent status bar and navigation bar, with insets applied:
My root view is a ContstraintLayout
. Somehow it's working even without fitsSystemWindows
and I'm getting the insets for both the top and bottom, which I've applied to my Toolbar
and FrameLayout
margins.
In the theme:
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
setImmersive
function in Activity
:
I've created this function to apply the insets and window flags required to achieve the immersive look for a layout which can have:
- Root view
- Top view
- Content
- Bottom view
/**
* Apply immersive mode to this activity
* @param rootView the root layout which will receive the window insets
* @param topView the top view to apply insets to (optional)
* @param bottomView the bottom view to apply insets to (optional)
*/
fun setImmersive(rootView: ViewGroup, topView: View? = null, bottomView: View? = null) {
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
bottomView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
rootView.setOnApplyWindowInsetsListener { _, insets ->
Log.d(javaClass.simpleName + " windowInsets", insets.toString())
// Apply the top insets
if (topView != null) {
insets.systemWindowInsetTop.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetTop $this")
val layoutParams = topView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = this
topView.layoutParams = layoutParams
}
}
}
// Apply the bottom insets
if (bottomView != null) {
insets.systemWindowInsetBottom.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetBottom $this")
val layoutParams = bottomView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.bottomMargin = this
bottomView.layoutParams = layoutParams
}
}
}
insets.consumeSystemWindowInsets()
}
}
Call this function in your onCreate
eg.:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.brand_activity)
setImmersive(root_view, topView = toolbar, bottomView = root_content)
}
The OnApplyWindowInsetsListener
on the root view was getting called twice, once with the correct insets WindowInsets{systemWindowInsets=Rect(0, 98 - 0, 168)
and again with 0 insets WindowInsets{systemWindowInsets=Rect(0, 0 - 0, 0)
. So I'm only setting margins on the non-zero insets.
In the layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_view">
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:id="@+id/root_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar_layout"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/toolbar_title"
android:textStyle="bold"
android:layout_gravity="center" />
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
add a comment |
Here's what I had to do to get both completely transparent status bar and navigation bar, with insets applied:
My root view is a ContstraintLayout
. Somehow it's working even without fitsSystemWindows
and I'm getting the insets for both the top and bottom, which I've applied to my Toolbar
and FrameLayout
margins.
In the theme:
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
setImmersive
function in Activity
:
I've created this function to apply the insets and window flags required to achieve the immersive look for a layout which can have:
- Root view
- Top view
- Content
- Bottom view
/**
* Apply immersive mode to this activity
* @param rootView the root layout which will receive the window insets
* @param topView the top view to apply insets to (optional)
* @param bottomView the bottom view to apply insets to (optional)
*/
fun setImmersive(rootView: ViewGroup, topView: View? = null, bottomView: View? = null) {
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
bottomView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
rootView.setOnApplyWindowInsetsListener { _, insets ->
Log.d(javaClass.simpleName + " windowInsets", insets.toString())
// Apply the top insets
if (topView != null) {
insets.systemWindowInsetTop.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetTop $this")
val layoutParams = topView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = this
topView.layoutParams = layoutParams
}
}
}
// Apply the bottom insets
if (bottomView != null) {
insets.systemWindowInsetBottom.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetBottom $this")
val layoutParams = bottomView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.bottomMargin = this
bottomView.layoutParams = layoutParams
}
}
}
insets.consumeSystemWindowInsets()
}
}
Call this function in your onCreate
eg.:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.brand_activity)
setImmersive(root_view, topView = toolbar, bottomView = root_content)
}
The OnApplyWindowInsetsListener
on the root view was getting called twice, once with the correct insets WindowInsets{systemWindowInsets=Rect(0, 98 - 0, 168)
and again with 0 insets WindowInsets{systemWindowInsets=Rect(0, 0 - 0, 0)
. So I'm only setting margins on the non-zero insets.
In the layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_view">
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:id="@+id/root_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar_layout"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/toolbar_title"
android:textStyle="bold"
android:layout_gravity="center" />
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Here's what I had to do to get both completely transparent status bar and navigation bar, with insets applied:
My root view is a ContstraintLayout
. Somehow it's working even without fitsSystemWindows
and I'm getting the insets for both the top and bottom, which I've applied to my Toolbar
and FrameLayout
margins.
In the theme:
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
setImmersive
function in Activity
:
I've created this function to apply the insets and window flags required to achieve the immersive look for a layout which can have:
- Root view
- Top view
- Content
- Bottom view
/**
* Apply immersive mode to this activity
* @param rootView the root layout which will receive the window insets
* @param topView the top view to apply insets to (optional)
* @param bottomView the bottom view to apply insets to (optional)
*/
fun setImmersive(rootView: ViewGroup, topView: View? = null, bottomView: View? = null) {
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
bottomView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
rootView.setOnApplyWindowInsetsListener { _, insets ->
Log.d(javaClass.simpleName + " windowInsets", insets.toString())
// Apply the top insets
if (topView != null) {
insets.systemWindowInsetTop.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetTop $this")
val layoutParams = topView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = this
topView.layoutParams = layoutParams
}
}
}
// Apply the bottom insets
if (bottomView != null) {
insets.systemWindowInsetBottom.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetBottom $this")
val layoutParams = bottomView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.bottomMargin = this
bottomView.layoutParams = layoutParams
}
}
}
insets.consumeSystemWindowInsets()
}
}
Call this function in your onCreate
eg.:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.brand_activity)
setImmersive(root_view, topView = toolbar, bottomView = root_content)
}
The OnApplyWindowInsetsListener
on the root view was getting called twice, once with the correct insets WindowInsets{systemWindowInsets=Rect(0, 98 - 0, 168)
and again with 0 insets WindowInsets{systemWindowInsets=Rect(0, 0 - 0, 0)
. So I'm only setting margins on the non-zero insets.
In the layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_view">
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:id="@+id/root_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar_layout"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/toolbar_title"
android:textStyle="bold"
android:layout_gravity="center" />
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
edited Feb 27 at 19:57
answered Feb 23 at 13:27
basharovVbasharovV
12
12
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53469643%2fonapplywindowinsetslistener-gives-systemwindowinsetbottom-that-is-always-0%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown