Jetpack Window Manager для складных устройств
В решении Jetpack Window Manager предоставляется стандартный API для работы со всеми складными устройствами. Он предусматривает два важных класса:
- DisplayFeature — обнаруживает разрывы в непрерывной плоской поверхности экрана, например петли или складки. WindowManager вернет коллекцию функций отображения при обратном вызове изменения макета.
- FoldingFeature — предоставляет сведения о конкретной функции устройства. В Surface Duo есть только одна функция складывания, но у других устройств их может быть больше.
Аналогичное руководство можно найти в практической работе по складным устройствам Android. Узнайте больше о разработке решений для складных устройств в документации по Android. Кроме того, на сайте GitHub доступны примеры от команды Android. В заметках о выпуске Jetpack фиксируются изменения в Window Manager по мере обновления.
Совет
Элементы управления и вспомогательные классы в библиотеке для двухэкранных устройств Surface Duo работают с Window Manager. Выполните инструкции, чтобы добавить нужные пакеты в свой проект приложения.
Чтобы использовать Window Manager непосредственно в коде, выполните приведенные ниже инструкции.
Добавление зависимостей
Убедитесь, что у вас есть репозиторий
mavenCentral()
в файле build.gradle верхнего уровня:allprojects { repositories { google() mavenCentral() } }
Убедитесь, что для
compileSdkVersion
иtargetSdkVersion
выбрана версия API 31 или выше в файле build.gradle на уровне модуля:android { compileSdkVersion 31 defaultConfig { targetSdkVersion 31 } ... }
Добавьте в файл уровня модуля build.gradle следующие зависимости:
dependencies { implementation "androidx.window:window:1.0.0" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0' }
Использование диспетчера окон в коде Kotlin
При доступе к свойствам Window Manager в проектах Kotlin важно настроить правильный поток информации. В противном случае вы можете получать слишком мало или слишком много обновлений событий, что может повлиять на производительность приложения.
Чтобы инициализировать и использовать объект WindowInfoTracker
, выполните следующие действия:
В классе MainActivity создайте переменную для
WindowInfoTracker
. Убедитесь, что в верхней части файла добавлена инструкцияimport androidx.window.layout.WindowInfoTracker
.class MainActivity : AppCompatActivity() { private lateinit var windowInfoTracker: WindowInfoTracker
Инициализируйте
WindowInfoTracker
в методе действияonCreate
и настройте поток для сбора сведений из свойстваwindowLayoutInfo
.override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize the window manager windowInfoTracker = WindowInfoTracker.getOrCreate(this@MainActivity) // Set up a flow lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { windowInfoTracker.windowLayoutInfo(this@MainActivity) .collect { // Check FoldingFeature properties here } } } }
Убедитесь, что в верхней части файла также добавлены следующие импортируемые компоненты:
import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch
Добавьте код, чтобы проверить поток
WindowLayoutInfo
на наличие свойств функций складывания. При выполнении этого кода действие будет обновлено с учетом текущего положения устройства и функций отображения (если приложение развертывается поверх сгиба или петли).В приведенном ниже фрагменте кода действие отображает другой текст на основе свойств
FoldingFeature
.В этом примере используется элемент TextView, называемый
layout_change_text
, который показывает тип загораживания и значениеisSeparating
для всех обнаруженных функций складывания.override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) windowInfoTracker = WindowInfoTracker.getOrCreate(this@MainActivity) lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { windowInfoTracker.windowLayoutInfo(this@MainActivity) .collect { newLayoutInfo -> layout_change_text.text = "No display features detected" for (displayFeature : DisplayFeature in newLayoutInfo.displayFeatures) { if (displayFeature is FoldingFeature && displayFeature.occlusionType == FoldingFeature.OcclusionType.NONE) { layout_change_text.text = "App is spanned across a fold, " + "isSeparating = ${displayFeature.isSeparating}" } if (displayFeature is FoldingFeature && displayFeature.occlusionType == FoldingFeature.OcclusionType.FULL) { layout_change_text.text = "App is spanned across a hinge, " + "isSeparating = ${displayFeature.isSeparating}" } } } } } }
Свойства функций складывания
Класс WindowLayoutInfo
содержит коллекцию элементов DisplayFeature
, один или несколько из которых могут быть экземплярами класса FoldingFeature.
Функции складывания имеют следующие свойства:
bounds
— координаты ограничивающего прямоугольника функции складывания;occlusionType
— если функция складывания скрывает содержимое (FULL
илиNONE
);orientation
— ориентация функции складывания (HORIZONTAL
илиVERTICAL
);state
— угол функции складывания (HALF_OPENED
илиFLAT
);isSeparating
— если функция складывания разделяет область отображения на две отдельные части.
Вы можете запросить эти свойства, чтобы принять решение о том, как настроить макет после изменения конфигурации.
isSeparating
При выборе места для элементов управления или количества отображаемых областей содержимого используйте свойство isSeparating. Благодаря этому полю ваше приложение обеспечит оптимальное взаимодействие с пользователем на всех складных устройствах:
- Для устройств с двумя экранами значение всегда будет true, если приложение развертывается поверх петли.
- Для других складных устройств значение будет true только в состоянии
HALF_OPENED
, например, если устройство стоит на столе.
Используйте свойство isSeparating
, чтобы решить, следует ли адаптировать макет пользовательского интерфейса приложения для складного устройства или использовать пользовательский интерфейс по умолчанию, если разделение отсутствует:
private fun updateCurrentLayout(newLayoutInfo: WindowLayoutInfo) {
for (displayFeature in newLayoutInfo.displayFeatures) {
val foldFeature = displayFeature as? FoldingFeature
foldFeature?.let {
if (it.isSeparating) {
// The content is separated by the FoldingFeature.
// Here is where you should adapt your UI.
} else {
// The content is not separated.
// Users can see and interact with your UI properly.
}
}
}
}
Ознакомьтесь с более подробным примером использования поля isSeparating.
Google также предоставляет документацию и примеры, связанные с этим свойством, в рамках своего руководства по складным устройствам и устройствам с большим экраном.
Примеры
Репозиторий surface-duo-jetpack-window-manager-samples на GitHub содержит несколько примеров Kotlin, демонстрирующих разные интерфейсы с поддержкой двух экранов, созданных с использованием Jetpack Window Manager и традиционной системы просмотра.
В репозитории surface-duo-compose-samples на GitHub также есть примеры Kotlin для устройств с двумя экранами, в которых используется Jetpack Window Manager, но в этих примерах пользовательский интерфейс построен с помощью Jetpack Compose.
API Java
Сведения о том, как получить доступ к классу WindowInfoTracker
через WindowInfoTrackerCallbackAdapter
, см. в записи блога, посвященной использованию Jetpack Window Manager с Java и этом примере Java.