36

我正在尝试了解 Android 操作系统,在阅读 Google I/O 2014 应用程序时,我遇到了WindowInsets. 如果有人能解释他们是什么,那将是一个很大的帮助。谢谢你。

4

3 回答 3

82

WindowInsets是应用于窗口的系统视图(例如状态栏、导航栏)的插入(或大小)。

在具体的例子中很容易理解。想象这个场景:

在此处输入图像描述

现在,您不想WindowInsets应用于 background ImageView,因为在这种情况下ImageView,状态栏高度会填充。

但是您确实希望将插图应用于Toolbar,因为否则Toolbar会在状态栏中间的某个位置绘制。

WindowInsets该视图通过以下方式声明了在 xml中应用的愿望:

android:fitsSystemWindows="true"

在此示例中,您不能将 应用于WindowInsets根布局,因为根布局会消耗WindowInsets,并且ImageView会被填充。

相反,您可以使用ViewCompat.setOnApplyWindowInsetsListener将插图应用于工具栏:

ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, insets) -> {
            ((ViewGroup.MarginLayoutParams) v.getLayoutParams()).topMargin =
                    insets.getSystemWindowInsetTop();
            return insets.consumeSystemWindowInsets();
        });

请注意,当Toolbar' 的根布局传递WindowsInsets给其子级时,将调用此回调。布局,例如FrameLayoutLinearLayoutDrawerLayout,,CoordinatorLayout做。

您可以对布局进行子类化,例如FrameLayout并覆盖onApplyWindowInsets

@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
    int childCount = getChildCount();
    for (int index = 0; index < childCount; index++)
        getChildAt(index).dispatchApplyWindowInsets(insets); // let children know about WindowInsets

    return insets;
}

Ian Lake在 medium上有一篇关于这些东西的不错的博客文章,还有 Chris Banes的“成为一个主要的窗户装配工”演示文稿。

我还在Medium 上创建了一篇关于WindowInsets 的详细文章。

更多资源:

于 2016-08-13T06:26:47.087 回答
12

Android系统使用屏幕的某些部分来渲染自己的内容,例如顶部的状态栏和底部的导航栏。例如,如果一个应用想要在底栏后面渲染,它应该考虑到底栏消耗的区域,否则应用 UI 会与系统 UI 冲突,你会得到这样的东西¹:

隐藏在底部栏后面的 FAB 按钮示例

在上面的图像上,应将额外的底部边距添加到 FAB 按钮,这样按钮就不会与底部栏相交。WindowInsets API允许您获取系统 UI使用的底部插图等信息。您经常会遇到fitsSystemWindows用于类似目的的属性,请参阅此答案以获取有关该属性的更多信息以及何时应该使用它而不是WindowInsets. 你也可以看看这篇很棒的文章:手势导航:处理视觉重叠(二)。等等,什么是手势导航

好吧,视觉重叠并不是您可能面临的唯一问题。从 Android 10 (API 29) 开始,添加了新的手势导航模式。现在用户可以选择使用手势在应用程序之间导航,而不是像上图那样使用按钮栏。现在强烈建议应用程序在导航栏后面绘制,以便用户拥有更现代的用户体验。但除此之外,还引入了一种新的插图类型——手势插图。事实证明,如果选择了手势导航模式,应用手势可能会与系统手势发生冲突。例如,让我们看一下下面的图片²:

与系统手势冲突的搜索栏示例

如您所见,搜索栏距离底部边缘太近,与系统快速切换手势冲突。由于系统手势具有更高的优先级,因此搜索栏变得不可用。手势导航:处理手势冲突(三)一文中很好地描述了这个示例以及其他常见场景。

我上面提到的文章是在 Android 团队工作的Chris Banes撰写的Gesture Navigation系列的一部分。如果您想更深入地了解主题,我建议您阅读整个系列。另一篇文章动画键盘(第 1 部分)可能也有帮助,它描述了 WindowInsets API 以及新的 IME 插入类型中的持续变化。

参考:


¹图片取自Gesture Navigation: going edge-to-edge (I)文章

²图片来自手势导航:处理手势冲突(三)

于 2020-10-31T19:01:47.157 回答
11

您可以在此处了解有关WindowInsets 的所有信息。WindowInsets为您提供应用程序可用的窗口区域。它本身并没有多大用处。当您覆盖View.onApplyWindowInsets或实施时,它的真正目的就来了View.OnApplyWindowInsetsListener。你可以在这里阅读它们:View.onApplyWindowInsetsView.OnApplyWindowInsetsListener

以自定义方式在视图上应用窗口插图的侦听器。

如果应用程序希望将自定义策略应用于处理视图的窗口插图的方式,则应用程序可以选择实现此接口。如果设置了 OnApplyWindowInsetsListener,则将调用其 onApplyWindowInsets 方法,而不是 View 自己的 onApplyWindowInsets 方法。侦听器可以选择调用参数 View 的 onApplyWindowInsets 方法来应用 View 的正常行为作为其自身的一部分。

简而言之,覆盖它可以让您控制可用于您的视图的窗口区域。

于 2015-11-09T13:06:26.177 回答