Перевод статьи подготовлен специально для студентов курса «Android-разработчик. Базовый курс». Также напоминаем о том, что мы продолжаем набор на расширенный курс «Специализация Android-разработчик»
![](https://habrastorage.org/r/w1560/webt/jn/f8/--/jnf8--c1dp0fowsqumsy7obnvbi.png)
![](https://habrastorage.org/webt/l6/83/t0/l683t0nbn6vonb7dbotjerud2wa.gif)
В Android Q Google попытался объединить все жесты навигации с помощью новой навигационной системы жестов, которая заменила плавающую навигационную панель (назад, домой и последние приложения).
Чтобы создать эффект погружения, приложения должны отображаться за строкой состояния и панелью навигации. Сначала сделаем строку состояния и панель навигации прозрачными.
Далее делаем так, чтобы
![](https://habrastorage.org/r/w1560/webt/u-/dv/wc/u-dvwcebklqibn25qn99msqrdc4.png)
FAB (Floating Action Button, плавающая кнопка действия) перекрывается плавающей панелью навигации. Плавающая панель навигации включена для наглядности.
Теперь, когда приложение отображается в полноэкранном режиме за (прозрачными) системными компонентами, возможно, что какой-то интерактивный компонент приложения перекрывается системным UI. Чтобы решить эту проблему, используйте Insets.
Insets — это набор значений, которые скажут нам, на сколько нужно переместить View, чтобы они не конфликтовали с системным UI. Эта информация предоставляется классом WindowInset. Начиная с API 20, Android предоставляет разработчикам System Window Insets (Insets системных окон), которые сообщают, сколько места занимают компоненты системы (такие как плавающая панель навигации и строка состояния). Эта информация может использоваться для перемещения интерактивных View, чтобы пользователь тапал по нему, а не по системному UI.
Для FAB задайте слушатель WindowsInsets и примените нижний inset окна в качестве нижнего отступа.
Точно так же, начиная с Android Q, система предоставляет insets навигационных жестов, чтобы перемещать свайпаемые views так, чтобы они не конфликтовали с жестами системы. Они предоставляются через Insets.getSystemGestureInsets()
![](https://habrastorage.org/r/w1560/webt/ns/pk/fi/nspkfinzrxups6mgjnqaf-rpoza.png)
Области системных жестов выделены желтым цветом.
Но что, если мы не хотим перемещать View и хотим разместить некоторый контент в тех зонах жестов, которые могут конфликтовать с приложением? В этих сценариях приложение может определять области, в которых приложение будет сначала обрабатывать событие касания, а не системные жесты. Это можно сделать, передав
В течение последнего года мы видели, что многие приложения начали поддерживать темные темы. Android Q добавляет этот переключатель в настройки системы.
Пользователь может включить темную тему тремя способами:
Чтобы поддерживать общесистемную конфигурацию Dark Theme, тема вашего приложения по умолчанию должна наследоваться от темы DayNight. Это связывает основную тему приложения с флагами ночного режима, управляемыми системой. Это работает путем извлечения ресурсов из папок квалификатора
Если вы заглянете внутрь стилей App Compat, вы заметите, что тема DayNight указывает на AppCompat Light в конфигурации по умолчанию и на AppCompat в ночной конфигурации.
Если вы хотите предоставить пользователям возможность управления темой из приложения, вы можете вызвать AppCompatDelegate.setDefaultNightMode(), который принимает один из четырех режимов:
а) Не хардкодьте цвета. Если в layout-файлах есть захардкоженные цвета, это тревожный звоночек. Замените их ссылками на
b) Проверьте изображения и предоставить им альтернативные ресурсы в рамках классификатора
c) В векторных рисунках не должно быть захардкоженных цветов. Используйте
d) Убедитесь, что все
e) Если приложение использует RemoteViews для уведомлений или виджетов, не забудьте также протестировать их. Хорошо, если приложение использует стили уведомлений по умолчанию, так как тогда система будет их обрабатывать.
f) Изменение конфигурации для
В Android Q также было представлено множество других вещей, которые я не рассматривал в деталях, такие как Панель настроек, новый API AudioPlaybackCapture (API дает приложениям возможность копировать звук, воспроизводимый другими приложениями. Эта функция является аналогом захвата экрана, но для аудио).
Наконец, Android Q включает в себя обновленный список ограниченных интерфейсов, не относящихся к SDK, доступ к которым в конечном итоге может быть закрыт из Android SDK. Вы можете найти список своих нарушений в play console в разделе «Отчет о тестировании» (Pre Launch Report).
На этом все. Если вы чувствуете, что есть что-то важное, о чем не сказано в статье, дайте знать в комментариях ниже. ;-)
![](https://habrastorage.org/webt/jn/f8/--/jnf8--c1dp0fowsqumsy7obnvbi.png)
О конфиденциальности и безопасности можно прочитать в первой части статьи.
2) User Experiences
а) Навигационные жесты
![](https://habrastorage.org/webt/l6/83/t0/l683t0nbn6vonb7dbotjerud2wa.gif)
В Android Q Google попытался объединить все жесты навигации с помощью новой навигационной системы жестов, которая заменила плавающую навигационную панель (назад, домой и последние приложения).
- На что влияет: если ваше приложение содержит жесты, то они могут конфликтовать с системными жестами. Это повлияет на все приложения, работающие на Android Q (независимо от целевого SDK), поскольку первыми будут обрабатываться системные жесты.
- Рекомендуемый подход: Поскольку плавающая панель навигации фактически исчезла, рекомендуется в полной мере использовать доступное новое экранное пространство и обеспечить пользователям эффект погружения.
Чтобы создать эффект погружения, приложения должны отображаться за строкой состояния и панелью навигации. Сначала сделаем строку состояния и панель навигации прозрачными.
<style name="AppTheme">
......
<item name="android:navigationBarColor">@android:color/transparent</item>
<!-- Optional, but recommended for full edge-to-edge rendering -->
<item name="android:statusbarColor">@android:color/transparent</item>
</style>
Далее делаем так, чтобы
Activity/View
отображалось на весь экран:view.systemUiVisibility =
//Layout as if the navigation bar was hidden
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or
//Layout as if the status bar was hidden
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or
//Layout at its most extreme
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
![](https://habrastorage.org/webt/u-/dv/wc/u-dvwcebklqibn25qn99msqrdc4.png)
FAB (Floating Action Button, плавающая кнопка действия) перекрывается плавающей панелью навигации. Плавающая панель навигации включена для наглядности.
Теперь, когда приложение отображается в полноэкранном режиме за (прозрачными) системными компонентами, возможно, что какой-то интерактивный компонент приложения перекрывается системным UI. Чтобы решить эту проблему, используйте Insets.
Insets — это набор значений, которые скажут нам, на сколько нужно переместить View, чтобы они не конфликтовали с системным UI. Эта информация предоставляется классом WindowInset. Начиная с API 20, Android предоставляет разработчикам System Window Insets (Insets системных окон), которые сообщают, сколько места занимают компоненты системы (такие как плавающая панель навигации и строка состояния). Эта информация может использоваться для перемещения интерактивных View, чтобы пользователь тапал по нему, а не по системному UI.
root.setOnApplyWindowInsetsListener { _, insets ->
val fabLp = fab.layoutParams as CoordinatorLayout.LayoutParams
fabLp.bottomMargin = fabOriginalBottomMargin + insets.systemWindowInsetBottom
fab.layoutParams = fabLp
insets.consumeSystemWindowInsets()
}
Для FAB задайте слушатель WindowsInsets и примените нижний inset окна в качестве нижнего отступа.
Точно так же, начиная с Android Q, система предоставляет insets навигационных жестов, чтобы перемещать свайпаемые views так, чтобы они не конфликтовали с жестами системы. Они предоставляются через Insets.getSystemGestureInsets()
![](https://habrastorage.org/webt/ns/pk/fi/nspkfinzrxups6mgjnqaf-rpoza.png)
Области системных жестов выделены желтым цветом.
Но что, если мы не хотим перемещать View и хотим разместить некоторый контент в тех зонах жестов, которые могут конфликтовать с приложением? В этих сценариях приложение может определять области, в которых приложение будет сначала обрабатывать событие касания, а не системные жесты. Это можно сделать, передав
List<
Rect>
в API View.setSystemGestureExclusionRects(), представленный в Android Q. Этот метод также доступен в ViewCompat с androidx.core:core:1.1.0
.- Подводные камни: вы можете отказаться от обработки только жестов “назад”. Границы жеста “домой” зарезервированы и не могут быть переопределены. Это сделано потому, что есть только один способ выйти из приложения. Если ваше приложение конфликтует с жестом “домой”, используйте
WindowInsets.getMandatorySystemGestureInsets()
, чтобы получить его границы и сместить ваши View.
б) Темная тема
В течение последнего года мы видели, что многие приложения начали поддерживать темные темы. Android Q добавляет этот переключатель в настройки системы.
Пользователь может включить темную тему тремя способами:
- Новый пункт в настройках системы (Настройки -> Дисплей -> Тема)
- Новый пункт в Быстрых Настройках
- В зависимости от производителя, можно включить через режим энергосбережения.
Чтобы поддерживать общесистемную конфигурацию Dark Theme, тема вашего приложения по умолчанию должна наследоваться от темы DayNight. Это связывает основную тему приложения с флагами ночного режима, управляемыми системой. Это работает путем извлечения ресурсов из папок квалификатора
night
.<!--App Compat Style-->
<style name="AppTheme" parent="Theme.AppCompat.DayNight">
<!--Material Components-->
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
Если вы заглянете внутрь стилей App Compat, вы заметите, что тема DayNight указывает на AppCompat Light в конфигурации по умолчанию и на AppCompat в ночной конфигурации.
<!--values/themes.xml-->
<style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat.Light">
<!--values-night/themes.xml-->
<style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat">
Если вы хотите предоставить пользователям возможность управления темой из приложения, вы можете вызвать AppCompatDelegate.setDefaultNightMode(), который принимает один из четырех режимов:
MODE_NIGHT_YES
— Показать темную темуMODE_NIGHT_NO
— Показать светлую темуMODE_NIGHT_FOLLOW_SYSTEM
— Следовать настройкам системыMODE_NIGHT_AUTO_BATTERY
— Включать темную тему, когда устройство переходит в режим энергосбережения.
- Подводные камни:
а) Не хардкодьте цвета. Если в layout-файлах есть захардкоженные цвета, это тревожный звоночек. Замените их ссылками на
color
. Еще лучше: используйте атрибуты для ссылки на цвета.b) Проверьте изображения и предоставить им альтернативные ресурсы в рамках классификатора
night
.c) В векторных рисунках не должно быть захардкоженных цветов. Используйте
tint
для стилизации векторных ресурсов с правильным цветом.d) Убедитесь, что все
color
ресурсы имеют соответствующие альтернативы в папке night
(values-night/colors.xml
)e) Если приложение использует RemoteViews для уведомлений или виджетов, не забудьте также протестировать их. Хорошо, если приложение использует стили уведомлений по умолчанию, так как тогда система будет их обрабатывать.
f) Изменение конфигурации для
uiMode
вызывается всякий раз, когда устройство переключается между обычным и темным режимом. Пользователь может сделать это вручную или активировать энергосберегающий режим. Если приложение не обрабатывает изменения конфигурации должным образом, UI теряет контекст, когда устройство переключается между обычным и темным режимами, поскольку видимые Activity и их фрагменты уничтожаются и создаются заново. Поэтому, даже если UI заблокирован в одной ориентации, добавьте поддержку изменения конфигурации. Кроме того, если приложение вручную управляет изменениями конфигурации через android:configChanges
, есть большая вероятность, что вы захотите также вручную управлять uiMode
. Например, если приложение использует непрерывное воспроизведение (видеопроигрыватель), оно может не захотеть прерывать воспроизведение только потому, что устройство переключилось между обычным и темным режимом.В Android Q также было представлено множество других вещей, которые я не рассматривал в деталях, такие как Панель настроек, новый API AudioPlaybackCapture (API дает приложениям возможность копировать звук, воспроизводимый другими приложениями. Эта функция является аналогом захвата экрана, но для аудио).
Наконец, Android Q включает в себя обновленный список ограниченных интерфейсов, не относящихся к SDK, доступ к которым в конечном итоге может быть закрыт из Android SDK. Вы можете найти список своих нарушений в play console в разделе «Отчет о тестировании» (Pre Launch Report).
На этом все. Если вы чувствуете, что есть что-то важное, о чем не сказано в статье, дайте знать в комментариях ниже. ;-)