Что такое WindowInsets?

Я пытаюсь узнать об ОС Android, и когда я читал приложение Google I/O 2014, я наткнулся на WindowInsets, Если кто-то может объяснить, что они из себя представляют, это будет очень полезно. Спасибо.

2 ответа

Решение

Вы можете узнать все о WindowInsets здесь.WindowInsets предоставляет вам область окна, которая может использоваться приложением. Само по себе это не очень полезно. Это истинная цель приходит, когда вы либо отменяете View.onApplyWindowInsets или реализовать View.OnApplyWindowInsetsListener, Вы можете прочитать о них здесь: View.onApplyWindowInsets и View.OnApplyWindowInsetsListener

Слушатель для наложения оконных вставок на вид нестандартным способом.

Приложения могут выбрать реализацию этого интерфейса, если они хотят применить пользовательскую политику к способу обработки оконных вставок для представления. Если установлен OnApplyWindowInsetsListener, его метод onApplyWindowInsets будет вызываться вместо собственного метода OnApplyWindowInsets представления. Слушатель может дополнительно вызвать метод onApplyWindowInsets параметра View, чтобы применить нормальное поведение View как часть его собственного.

Короче говоря, переопределение этого позволит вам контролировать область окна, доступную для вашего просмотра.

WindowInsets являются вставками (или размерами) системных видов (например, строка состояния, панель навигации), которые применяются к окну.

Это было бы легко понять на конкретном примере. Изображение этого сценария:

введите описание изображения здесь

Теперь вы не хотите WindowInsets быть примененным к фону 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 своим детям. Макеты как FrameLayout, LinearLayout не делайте, DrawerLayout, 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;
}

Есть хорошая публикация в блоге Иана Лейка на эту тему, а также презентация Криса Бэйнса "Как стать мастером окон".

Я также создал подробную статью в Medium, касающуюся WindowInsets.

Больше ресурсов:

Система Android использует некоторые части экрана для отображения собственного содержимого, например строку состояния вверху и панель навигации внизу. Например, если приложение хочет отображать за нижней панелью, оно должно учитывать площадь, занимаемую нижней панелью, иначе пользовательский интерфейс приложения будет конфликтовать с пользовательским интерфейсом системы, и вы получите что-то вроде этого¹:

Пример кнопки FAB, которая скрыта за нижней панелью

На изображении выше следует добавить дополнительное нижнее поле к кнопке FAB, чтобы кнопка не пересекала нижнюю панель. WindowInsets API позволяет получить такую ​​информацию, как нижняя вставка, которую использует пользовательский интерфейс системы. Часто можно встретить fitsSystemWindowsатрибут, который служит аналогичной цели, см. этот ответ для получения дополнительной информации об атрибуте и о том, когда вы должны использовать его вместо WindowInsets. Вы также можете взглянуть на эту замечательную статью: Навигация с помощью жестов: обработка визуальных перекрытий (II). Подождите, что такое навигация с помощью жестов?

Что ж, визуальные совпадения - не единственная проблема, с которой вы можете столкнуться. Начиная с Android 10 (API 29) был добавлен новый режим навигации с помощью жестов. Теперь пользователь может выбрать использование жестов для перехода между приложениями вместо панели кнопок, как на изображении выше. Теперь приложениям настоятельно рекомендуется рисовать за панелью навигации, чтобы у пользователей был более современный интерфейс. Но помимо этого был введен новый вид вставок - жестовые вставки. Оказывается, жесты приложения могут конфликтовать с жестами системы, если выбран режим навигации с помощью жестов. Например, давайте посмотрим на следующее изображение²:

Как видите, полоса поиска расположена слишком близко к нижнему краю, и это конфликтует с жестом быстрого переключения системы. Поскольку системные жесты имеют более высокий приоритет, панель поиска становится непригодной для использования. Эти примеры, а также другие распространенные сценарии хорошо описаны в статье " Навигация с помощью жестов: обработка конфликтов жестов" (III).

Статьи, о которых я упомянул выше, являются частью серии Gesture Navigation, написанной Крисом Бэйнсом, который работает в команде Android. Если вы хотите получить более глубокое представление о теме, я рекомендую вам прочитать всю серию. Другая статья " Анимация клавиатуры" (часть 1) тоже может быть полезной, в ней описаны текущие изменения в API WindowInsets, а также новый тип вставок IME.

Справка:


¹ Изображение взято из статьи " Навигация жестами: от края до края" (I)

² Изображение взято из статьи " Навигация жестов: устранение конфликтов жестов" (III).

Другие вопросы по тегам