WindowInsets是什么?

43

我正在尝试学习关于Android操作系统,当我阅读Google I/O 2014应用程序时,我遇到了WindowInsets。如果有人能够解释它们是什么,那将是一大帮助。谢谢。

我正尝试了解Android操作系统,当我阅读Google I/O 2014应用程序时,我遇到了 WindowInsets。如果有人能够解释这是什么,那将会非常有帮助。谢谢。
3个回答

87

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

通过具体示例很容易理解。想象一下这种情况:

enter image description here

现在,您不希望将WindowInsets应用于背景ImageView,因为这样ImageView将被状态栏高度填充。

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

该视图通过以下方式在xml中声明希望应用WindowInsets

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传递给其子项时,将调用此回调函数。像FrameLayoutLinearLayout这样的布局不会传递,而DrawerLayoutCoordinatorLayout会传递。
您可以创建自己的布局子类,例如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;
}

有一篇关于这方面的好博客文章在medium上由Ian Lake撰写, 还有Chris Banes撰写的"成为窗户安装大师"演示在此处

我还创建了一篇详细的Medium文章关于WindowInset的内容

更多资源:


那么,为了在LinearLayout中应用插图,我需要对其进行子类化,对吗? - Enrico Bruno Del Zotto
1
你会如何处理这个 Android 5.0 (Lollipop) 之前的问题呢?似乎需要使用 WindowInsetsCompat 的 compat 版本的 dispatchApplyWindowInsets。 - Fhl

15

Android系统使用屏幕的某些部分来渲染自己的内容,例如顶部的状态栏和底部的导航栏。如果应用程序想要在底部栏后面进行渲染,它应该考虑到底部栏占用的区域,否则应用程序界面将与系统界面冲突,会出现类似于这样的情况¹:

An example of a FAB button which is hidden behind the bottom bar

在上面的图像中,应该向FAB按钮添加额外的底边距,以使按钮不与底部栏相交。WindowInsets API允许您获取系统UI消耗的底部插入等信息。您经常会遇到fitsSystemWindows属性,其具有类似的目的,请参阅this answer了解有关属性的更多信息以及何时应该使用它而不是WindowInsets。您还可以查看这篇很棒的文章:Gesture Navigation: handling visual overlaps (II)。等等,什么是 Gesture Navigation
好吧,视觉重叠不是您可能会遇到的唯一问题。自Android 10(API 29)以来,添加了新的 Gesture Navigation 模式。现在,用户可以选择使用手势在应用程序之间导航,而不是像上面图像中的按钮栏。现在强烈建议应用程序在导航栏后面进行绘制,以便用户拥有更现代化的UX。但除此之外,还引入了新的插入类型 - 手势插入。事实证明,如果选择了 Gesture Navigation 模式,则应用程序手势可能会与系统手势发生冲突。例如,让我们看一下以下图像²:

An example of a seek-bar which conflicts with the system gestures

如您所见,进度条离底部太近,与系统快速切换手势冲突。由于系统手势具有更高的优先级,因此进度条变得无法使用。这些示例以及其他常见情况在手势导航:处理手势冲突(III)文章中有很好的描述。
上述文章是由Android团队成员Chris Banes撰写的手势导航系列的一部分。如果您想深入了解该主题,我建议您阅读整个系列。另一篇文章动画化您的键盘(第1部分)也可能会有所帮助,它描述了WindowInsets API中正在进行的更改以及新的IME插图类型。
参考:

¹ 该图片来自于手势导航:边缘到边缘(I)文章

² 该图片来自于手势导航:处理手势冲突(III)文章


13
您可以在这里学习有关 WindowInsets 的全部内容。 WindowInsets 为您提供应用程序可用的窗口区域。它本身并没有什么用处。当您覆盖 View.onApplyWindowInsets 或实现 View.OnApplyWindowInsetsListener 时,才能发挥其真正的作用。您可以在这里阅读有关它们的信息:View.onApplyWindowInsetsView.OnApplyWindowInsetsListener

自定义视图应用窗口插图的侦听器。

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

简而言之,覆盖此方法将让您控制您的视图可用的窗口区域。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接