onApplyWindowInsets вызывается со странной верхней вставкой

У меня есть приложение для 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 он был передан, затем вызывает метод суперкласса, регистрирует результат и возвращает его - ничего не изменяется. Журнал также показывает, что метод суперкласса не изменяет вставки.

Теперь я получаю странно выглядящий верхний вкладыш, который всегда кажется на 56–72 дп больше, чем я ожидал:

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 пикселя в верхней части моего представления, она отображается в верхней части видимой области (т. Е. Под строкой состояния, если она есть), никогда не за кадром.

Если бы я доверял этим значениям врезки и смещению содержимого на количество пикселей, указанное для того, чтобы оно не касалось системных панелей, я бы закончил с пропуском в верхней части представления.

Насколько я могу судить, значения влево / вправо / вниз кажутся нормальными.

Как я могу это исправить? Я что-то пропускаю?

1 ответ

Решение

Поскольку у меня до сих пор нет объяснения представленных значений, я предполагаю, что это либо ошибка, либо плохо документированная функция, которая, тем не менее, присутствует во многих (если не во всех) версиях Android.

К счастью, по крайней мере в API 23+ есть еще один способ получить вставки окна, а именно: View#getWindow().getRootView().getRootWindowInsets(), Кажется, в этом есть свои ошибки, а именно сообщение о неправильных вставках для панели навигации, но объединение двух результатов сработало для меня.

  • Храните вставки, переданные onApplyWindowsInsets(), отбрасывая только верхний.
  • Override onSizeChanged() для просмотра, и в нем зовут View#getRootWindowInsets() чтобы получить верхнюю вставку (игнорировать другие).

Объединенные ценности работали для меня.

К сожалению, это не будет работать на API 20–22, который не реализует View#getRootWindowInsets(), Здесь вам нужно будет сделать некоторые догадки. К счастью, это проще, поскольку эти API еще не реализуют разделенный экран - верхняя вставка будет высотой строки состояния, если вы явно не запросили ее скрытие (в этом случае это 0). Если строка состояния видна, ее высоту можно определить следующим образом:

Resources resources = view.getResources();
int shid = resources.getIdentifier("status_bar_height", "dimen", "android");
padding_top = (shid > 0) ? resources.getDimensionPixelSize(shid) : 0;
Другие вопросы по тегам