我想计算导航栏的高度。我看过这个演示文稿:https://chris.banes.me/talks/2017/becoming-a-master-window-fitter-nyc/
因此,我尝试使用该方法View.setOnApplyWindowInsetsListener()
.但是,由于某种原因,它从未被调用过。
有谁知道为什么?有什么限制吗?
我尝试像这样使用它:
navBarOverlay.setOnApplyWindowInsetsListener { v, insets ->
Timber.i("BOTTOM = ${insets.systemWindowInsetBottom}")
return@setOnApplyWindowInsetsListener insets
}
请注意,我的根布局是一个ConstraintLayout
。
我遇到了同样的问题。
如果您的根视图是 ConstraintLayout 并且包含 android:fitsSystemWindows="true" attr,则该视图在 ApplyWindowInsets 上使用回调。因此,如果在子视图上设置 onApplyWindowInset,它们永远不会获得 onApplyWindowInsets 回调。
或者检查父视图是否使用了回调。
这就是我观察到的;换句话说,你的体验可能会有所不同。
[Layout for Activity]
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" <--
tools:context=".MyAppActivity">
...
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
请注意android:fitsSystemWindows="true"
在最外层的布局中。只要我们拥有它,setOnApplyWindowInsetsListener()
就会被召唤。
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
ViewCompat.setOnApplyWindowInsetsListener(fab) { view, insets ->
...
insets
}
}
或者,如果您要使用"全屏",这意味着您希望布局扩展到状态栏和导航栏,则可以执行以下操作。
override fun onCreate(savedInstanceState: Bundle?) {
...
WindowCompat.setDecorFitsSystemWindows(window, false) <--
ViewCompat.setOnApplyWindowInsetsListener(fab) { view, insets ->
...
insets
}
}
同样的想法也适用于使用片段,只要活动(包含片段)在最外层布局中fitsSystemWindows
,或者您将活动设置为全屏。
使用CollapsingToolbarLayout
时遇到了这个问题,问题是CollapsingToolbarLayout
不调用插入侦听器,如果您有CollapsingToolbarLayout
,那么在此组件之后,所有其他视图插入都不会被触发。如果是这样,则通过调用从CollapsingToolbarLayout
中删除侦听器
ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, null)
如果不CollapsingToolbarLayout
,则其他某个视图会阻止插图从一个视图传递到另一个视图。
或者你已经吃过它们了,我猜你没有这样做)
CollapsingToolbarLayout
也有bug,它可以阻止兄弟姐妹接收插图,你可以在问题github链接中看到它。解决方案之一是将下面的AppbarLayout
放在xml其他视图中,以便它们接收插图。
我不得不(我想我应该)在某个适当的时间显式调用requestApplyInsets()以使听众受到打击。
查看本文以获取一些可能的提示:https://medium.com/androiddevelopers/windowinsets-listeners-to-layouts-8f9ccc8fa4d1
我在 API 30 上遇到了类似的问题。要使setOnApplyWindowInsetsListener()正常工作,您必须确保您的活动处于全屏模式。您可以使用以下方法执行此操作
WindowCompat.setDecorFitsSystemWindows(activity.window, false) //this is backward compatible version
还要确保你没有在任何地方使用以下方法来设置 UI 标志
View.setSystemUiVisibility(int visibility)
我为我在 28 到 26 的 API 上的情况找到了解决方案。因为在更高版本上一切都很好。
首先,我需要提一下,我已经尝试了上面答案中提到的所有内容,但没有任何帮助。
解决方案:
ViewCompat.setOnApplyWindowInsetsListener(your_parent_view) { v, insets ->
var consumed = false
(v as ViewGroup).forEach { child ->
// Dispatch the insets to the child
val childResult = ViewCompat.dispatchApplyWindowInsets(child, insets)
// If the child consumed the insets, record it
if (childResult.isConsumed) {
consumed = true
}
}
// If any of the children consumed the insets, return an appropriate value
if (consumed) WindowInsetsCompat.CONSUMED else insets
}
就我而言your_parent_view
是一个FragmentViewContainer
,我的片段位于我要添加填充的AppBarLayout
。
这不是我的发现,这在克里斯·贝恩斯的文章中提到,作为另一个问题的修复。
此外,我删除了所有fitsSystemWindows=true
行,并将此属性仅保留在我的AppBarLayout
中,在当前片段中。
当然,此行应添加到您的活动中:
WindowCompat.setDecorFitsSystemWindows(window, false)
不需要额外的ViewCompat.setOnApplyWindowInsetsListener(appBarLayout)
。fitsSystemWindows=true
属性正在发挥作用。
我的解决方案是在navBarOverlay.rootView
上调用它。
将ViewCompat.setOnApplyWindowInsetsListener
放入onResume
对我使用约束布局有用。
@Override
public void onResume() {
super.onResume();
ViewCompat.setOnApplyWindowInsetsListener(requireActivity().getWindow().getDecorView(), (v, insets) -> {
boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
return insets;
});
}
我在 android 7.1 上遇到了这个问题。但是在 android 11 上它工作正常。只需创建一个类:
import android.content.Context
import android.util.AttributeSet
import androidx.core.view.ViewCompat
import com.google.android.material.appbar.CollapsingToolbarLayout
class InsetsCollapsingToolbarLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : CollapsingToolbarLayout(context, attrs, defStyle) {
init {
ViewCompat.setOnApplyWindowInsetsListener(this, null)
}
}
并在任何地方使用 InsetCollapsingToolbarLayout 而不是 CollapsingToolbarLayout
在我的应用程序中,它被调用一次,而不是每次我都调用。因此,在它被调用的那一次中,我将 widnowInsets 保存到全局变量中,以便在整个应用程序中使用它。
我使用此答案使用以下解决方案:
ViewCompat.setOnApplyWindowInsetsListener(
findViewById(android.R.id.content)
) { _: View?, insets: WindowInsetsCompat ->
navigationBarHeight = insets.systemWindowInsetBottom
insets
}
我在项目中使用以下解决方案,它就像一个魅力。
val decorView: View = requireActivity().window.decorView
val rootView = decorView.findViewById<View>(android.R.id.content) as ViewGroup
ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
val isKeyboardVisible = isKeyboardVisible(insets)
Timber.d("isKeyboardVisible: $isKeyboardVisible")
// Do something with isKeyboardVisible
insets
}
private fun isKeyboardVisible(insets: WindowInsetsCompat): Boolean {
val systemWindow = insets.systemWindowInsets
val rootStable = insets.stableInsets
if (systemWindow.bottom > rootStable.bottom) {
// This handles the adjustResize case on < API 30, since
// systemWindow.bottom is probably going to be the IME
return true
}
return false
}
在 Android API 中使用setWindowInsetsAnimationCallback
而不是setOnApplyWindowInsetsListener
> 30
我遇到的一个问题是ViewCompat.setOnApplyWindowInsetsListener
在代码中的其他地方再次调用了同一视图。因此,请确保仅设置一次。