setOnApplyWindowInsetsListener 从未调用过



我想计算导航栏的高度。我看过这个演示文稿: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在代码中的其他地方再次调用了同一视图。因此,请确保仅设置一次。

相关内容

  • 没有找到相关文章

最新更新