onApplyWindowInsets 用奇怪的顶部插图调用

onApplyWindowInsets called with strange top inset

我有一个 Android 应用程序,其主题设置如下:

<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>

<item name="android:windowDrawsSystemBarBackgrounds">true</item>

层次结构中的顶层视图覆盖 onApplyWindowsInsets()。该实现仅记录它传递的 WindowInsets,然后调用超类方法,记录结果和 returns——没有任何修改。日志还显示超类方法不修改插图。

现在我得到了一个看起来很奇怪的顶部插图,它似乎总是比我预期的多 56-72 dp:

Platform           DPI    Layout                  Inset         Bar          Difference

Android x86_64 8.1 MDPI   Landscape               88 px/dp      24 px/dp     64 px/dp
                          Landscape, split        80 px/dp      24 px/dp     56 px/dp
Anbox              MDPI   Window                  64 px/dp      None         64 px/dp
LineageOS 15.1     XXHDPI Portrait                240 px/80 dp  72 px/24 dp  168 px/56 dp
                          Portrait, split/top     216 px/73 dp  72 px/24 dp  144 px/48 dp
                          Portrait, split/bottom  144 px/48 dp  None         144 px/48 dp
SDK Emulator (6.0) HDPI   Portrait                120 px/80 dp  36 px/24 dp  84 px/56 dp

注意:在横向模式下,有两次连续调用onApplyWindowInsets(),这里只报告最后一次。

视图实际上并没有超出可见区域的顶部:如果我在视图顶部绘制一个 24 像素的区域,它会出现在可见区域的顶部(即状态栏下方,如果有一个),永远不会离开屏幕。

如果我相信这些插入值并根据指示的像素数偏移内容以使其远离系统栏,我最终会在视图顶部出现间隙。

Left/right/bottom 据我所知,值似乎还不错。

我该如何纠正这个问题?我是不是忽略了什么?

由于我仍然无法解释所报告的值,我认为这可能是一个错误或记录不完整的功能,尽管如此,它仍然存在于 Android 的许多(如果不是全部)版本中。

幸运的是,至少在 API 23+ 上,还有另一种获取 window 插入的方法,即调用 View#getWindow().getRootView().getRootWindowInsets()。这似乎有 ,即报告导航栏的不正确插入,但合并这两个结果对我有用。

  • 存储传递给 onApplyWindowsInsets() 的插图,仅丢弃顶部的插图。
  • 为视图覆盖 onSizeChanged(),并在其中调用 View#getRootWindowInsets() 以获得顶部插图(忽略其他)。

组合值对我有用。

不幸的是,这不适用于 API 20–22,它没有实现 View#getRootWindowInsets()。在这里,您需要做一些猜测。幸运的是,这更容易,因为这些 APIs 还没有实现分屏——顶部插图将是状态栏的高度,除非你明确要求隐藏它(在这种情况下它是 0) .如果状态栏是可见的,它的高度可以确定如下:

Resources resources = view.getResources();
int shid = resources.getIdentifier("status_bar_height", "dimen", "android");
padding_top = (shid > 0) ? resources.getDimensionPixelSize(shid) : 0;