19

我想计算导航栏的高度。我看过这个演示文稿: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.

4

12 回答 12

9

我遇到了同样的问题。

如果您的根视图是 ConstraintLayout 并且包含 android:fitsSystemWindows="true" attr,则该视图使用 onApplyWindowInsets 回调。因此,如果您在子视图上设置 onApplyWindowInsets,它们将永远不会获得 onApplyWindowInsets 回调。

或检查您的父视图是否使用回调。

于 2019-11-21T09:41:28.390 回答
4

我在使用时遇到过这个问题CollapsingToolbarLayout,问题是CollapsingToolbarLayout没有调用 insets 监听器,如果你有CollapsingToolbarLayout,那么在这个组件之后,所有其他视图 insets 都不会被触发。CollapsingToolbarLayout如果是这样,则通过调用删除侦听器

ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, null)

如果你不这样做CollapsingToolbarLayout,那么其他一些视图会阻止插图从一个视图传递到另一个视图。

或者你已经吃过了,我猜你没有这样做)

于 2020-11-05T12:26:21.183 回答
3

这是我观察到的;换句话说,您的体验可能会有所不同。

[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
    }
}

当您使用 Fragment 时,同样的想法也适用,只要 Activity(包含 Fragment)fitsSystemWindows位于最外层布局中,或者您将 Activity 设置为全屏。

于 2020-11-04T19:09:51.387 回答
2

还有一个错误CollapsingToolbarLayout,它会阻止兄弟姐妹接收插图,您可以在问题 github 链接中看到它。解决方案之一是AppbarLayout在 xml 下方放置其他视图,以便它们接收插图。

于 2020-11-06T06:05:00.533 回答
1

我在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)
    }

}

并在任何地方使用 InsetsCollapsingToolbarLayout 而不是 CollapsingToolbarLayout

于 2021-09-24T13:20:55.720 回答
1

我在 API 30 上遇到了类似的问题。要使 setOnApplyWindowInsetsListener() 工作,您必须确保您的活动处于全屏模式。您可以使用以下方法来做到这一点

WindowCompat.setDecorFitsSystemWindows(activity.window, false) //this is backward compatible version

还要确保您没有在任何地方使用以下方法来设置 UI 标志

View.setSystemUiVisibility(int visibility)
于 2021-06-23T09:49:31.417 回答
0

使用约束布局为我工作ViewCompat.setOnApplyWindowInsetsListeneronResume

@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;
        });
} 
于 2021-06-02T10:40:27.523 回答
0

我的解决方案是调用它navBarOverlay.rootView

于 2020-08-14T09:36:39.390 回答
0

我不得不(并且我认为我应该)在某个适当的时间显式调用 requestApplyInsets() 以使侦听器受到打击。

查看这篇文章以获取一些可能的提示:https ://medium.com/androiddevelopers/windowinsets-listeners-to-layouts-8f9ccc8fa4d1

于 2019-05-22T17:34:53.600 回答
0

我在我的项目中使用了以下解决方案,它就像一个魅力。

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 > 30 中使用setWindowInsetsAnimationCallback而不是setOnApplyWindowInsetsListener

于 2021-07-03T08:57:42.220 回答
0

我使用答案使用了以下解决方案:

ViewCompat.setOnApplyWindowInsetsListener(
        findViewById(android.R.id.content)
    ) { _: View?, insets: WindowInsetsCompat ->
        navigationBarHeight = insets.systemWindowInsetBottom
        insets
    }
于 2021-03-06T10:22:30.467 回答
0

在我的应用程序中,它会被调用一次,而不是每次我想调用的时候。因此,在那一次它被调用时,我将 widnowInsets 保存到一个全局变量中,以便在整个应用程序中使用它。

于 2019-08-27T07:18:08.943 回答