[英]Go edge-to-edge on Android correctly with WindowInsets
I'm trying to get edge-to-edge ( https://youtu.be/OCHEjeLC_UY?t=1635 ) working correctly on API 21 up to 29.我正在尝试让边缘到边缘( https://youtu.be/OCHEjeLC_UY?t=1635 )在 API 21 到 29 上正常工作。
I'm using this on my v27\\themes.xml
:我在我的
v27\\themes.xml
上使用它:
<item name="android:windowLightNavigationBar">true</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
And this in my Activity:这在我的活动中:
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
}
}
Plus, I'm setting android:fitsSystemWindows=true
on my AppBarLayout
.另外,我在
AppBarLayout
上设置了android:fitsSystemWindows=true
。
With that in place, it looks fine on API >= 27 where the content scrolls behind the now transparent navigation bar but on older APIs, the content is covered by the black navigation bar.有了它,它在 API >= 27 上看起来很好,其中内容在现在透明的导航栏后面滚动,但在较旧的 API 上,内容被黑色导航栏覆盖。
I know that I need to get the WindowInsets
and add it to my existing padding (or in case of AppBarLayout
it will handle the insets itself), but I cannot get it to work with a FAB.我知道我需要获取
WindowInsets
并将其添加到我现有的填充中(或者在AppBarLayout
的情况下,它将自己处理插图),但我无法让它与 FAB 一起使用。
I found this article about adding the inset to the padding
of a view but because the FAB uses margin
I'm not sure, if I'm on the right track.我发现这篇文章是关于将插图添加到视图的
padding
中,但由于 FAB 使用margin
,我不确定我是否走在正确的轨道上。
Is there any documentation, example, best practice on how to handle insets when going edge-to-edge?是否有任何文档,例如,关于如何在边缘到边缘处理插入的最佳实践? It seems that some widgets like
AppBarLayout
handle it gracefully but how can I get the FAB to adjust its margin as well?似乎
AppBarLayout
之类的一些小部件可以优雅地处理它,但我怎样才能让 FAB 也调整其边距?
To specify, when adding android:fitsSystemWindows=true
to CoordinatorLayout
it handles the insets as well but with a major drawback:要指定,当将
android:fitsSystemWindows=true
添加到CoordinatorLayout
时,它也会处理插入,但有一个主要缺点:
I have two layouts, each with a CoordinatorLayout
: "parent layout" defines a CoordinatorLayout
with a AppBarLayout
and a FrameLayout
to hold the actual content and "child layout" used by a Fragment placed in the latter.我有两个布局,每个布局都有一个
CoordinatorLayout
:“父布局”定义了一个带有AppBarLayout
的CoordinatorLayout
和一个FrameLayout
来保存放置在后者中的 Fragment 使用的实际内容和“子布局”。
Because of this, I cannot add android:fitsSystemWindows=true
to the child layout because it would result in a blank space on top (between the toolbar and the content) and I cannot put it in the parent layout because then the FAB won't be updated to the insets.因此,我无法将
android:fitsSystemWindows=true
添加到子布局中,因为它会导致顶部(工具栏和内容之间)有一个空白区域,并且我不能将它放在父布局中,因为这样 FAB 不会更新到插图。
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 (eg AppBarLayout
or FloatingActionButton
). 不要在任何地方使用
android:fitsSystemWindows
,而android:fitsSystemWindows
插图手动应用于屏幕边缘的任何视图,否则这些视图会滑入系统栏后面(例如AppBarLayout
或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 ): 我编写了一些帮助程序,以将插图添加到padding或margin中,并尊重任何先前添加的插图(需要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. 例如,只需调用
fab.addSystemWindowInsetToMargin(bottom = true)
,FAB就会在导航栏上方上移。 Or app_bar.addSystemWindowInsetToPadding(top = true)
to keep the app bar below the status bar (mind the margin/padding difference). 或
app_bar.addSystemWindowInsetToPadding(top = true)
将应用程序栏保持在状态栏下方(注意边距/填充差异)。
As per https://developer.android.com/training/gestures/edge-to-edge#kotlin根据https://developer.android.com/training/gestures/edge-to-edge#kotlin
Just use this on BaseActivity or any activity you want:只需在 BaseActivity 或您想要的任何活动上使用它:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
}
NB: Do not use anywhere this注意:不要在任何地方使用这个
android:fitsSystemWindows="true"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.