Я познакомился с Jetpack Compose на начальном этапе его разработки. Это было на заре 2020 года, и уже тогда я был впечатлен новым способом реализации UI.
К сожалению, на тот момент в большинстве функциональностей отсутствовали обработка обратного стека, выпадающее меню, навигация и т.д. Но все это дела уже минувших дней, а мы возвращаемся назад в будущее — в 2023 год. Наконец-то Jetpack Compose приведен в состояние рабочей готовности. Он предоставляет отличные API совместимости, как никогда упрощая процесс перехода.
Преимущества Jetpack Compose
Jetpack Compose — современный набор инструментов для создания UI с рядом преимуществ. Особенно отметим возможность перехода на один язык программирования для всего приложения, что позволяет избавиться от XML-файлов.
Он облегчил и ускорил разработку UI за счет значительного сокращения шаблонного кода, который использовался в императивном UI для поиска представлений и настройки логики UI, поскольку логика в декларативном UI встроена внутри компонентов. Помимо этого, Jetpack Compose сильно упрощает создание анимации с состояниями, значения которых можно легко менять в среде выполнения.
Кроме того, навигация с Jetpack Compose становится намного удобнее, поскольку установка всех правил внутри XML-файлов сопровождалась чрезвычайными сложностями. Еще одно преимущество заключается в повышении производительности при запуске View, так как макеты компилируются подобно остальной части приложения и не требуют расширения. После полного перехода на Compose уменьшаются как размер приложения, так и время сборки.
С чего начать?
Уже используемый UI на основе представлений не требует сразу полной перезаписи. Обеспечиваемая поддержка совместимости позволяет Compose и View сосуществовать в базе кода. Благодаря этому вы можете добавлять новые функциональности с помощью Compose или переносить в него небольшие имеющиеся компоненты. По мере готовности и принятия Compose вы воспользуетесь рекомендуемой стратегией перехода, называемой восходящим подходом. Он основывается на поочередной перезаписи небольших представлений с экрана до того момента, пока вы не сможете перенести ViewGroup
и RootView
в Compose.
В следующих разделах вы узнаете:
- как настроить среду для Compose;
- какие возможны сценарии;
- как реализовать Compose во View и View в Compose;
- как обрабатывать фрагменты
Fragment
в Compose.
Настройка Gradle
В buildFeatures
активируем Compose
и ViewBinding
, затем добавляем основные зависимости Compose:
android {
...
buildFeatures {
compose true
viewBinding true
}
composeOptions {
kotlinCompilerExtensionVersion '1.3.2'
}
}
dependencies {
...
implementation "androidx.activity:activity-compose:$version"
implementation "androidx.compose.runtime:runtime-livedata:$version"
implementation "androidx.compose.ui:ui:$version"
implementation "androidx.compose.ui:ui-tooling-preview:$version"
implementation "androidx.compose.material:material:$version"
implementation "androidx.compose.ui:ui-viewbinding:$version"
implementation "androidx.navigation:navigation-compose:$version"
}
Compose в View
ComposeView
в макете XML. ДобавляемComposeView
в макет XML:
<androidx.compose.ui.platform.ComposeView
android:id="@+id/composeView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Получаем доступ в Compose
из макета XML:
binding.composeView.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
Text(text = "Hello in Compose World!")
}
}
}
ComposeView
непосредственно как макет. РеализуемComposeView
как представление виджета и получаем доступ в Compose:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View = ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
Text(text = "Hello in Compose World!")
}
}
}
ViewCompositionStrategy для ComposeView
Существуют 4 стратегии композиции представлений для ComposeView
. По умолчанию Compose удаляет композицию каждый раз, когда представление отсоединяется от окна. Однако в некоторых случаях применение этого значения по умолчанию не рекомендовано:
DisposeOnDetachedFromWindow
;DisposeOnDetachedFromWindowOrReleasedFromPool
(по умолчанию);DisposeOnLifecycleDestroyed
;DisposeOnViewTreeLifecycleDestroyed
(Fragment
,Transition
, пользовательские представления с учетомLifecycle
).
View в Compose
AndroidView
для пользовательских представлений. Создаем пользовательское представление вfactory
, а также настраиваем слушателей события клика и обратные вызовы для взаимодействия View -> Compose. Затем при обновлении настраиваем взаимодействие для Compose -> View:
@Composable
fun XMLCounter() {
var resultState by remember { mutableStateOf(0) }
AndroidView(
factory = { context ->
CounterView(context).apply {
// Пример взаимодействия View -> Compose
resultCallback = {
resultState = it
}
}
},
update = { counterView ->
// Пример взаимодействия Compose -> View
counterView.binding.result.text = resultState.toString()
}
)
AndroidViewBinding
. РасширяемViewBinding
в Compose и получаем доступ к классуBinding
:
@Composable
fun XMLCounterBinding() {
AndroidViewBinding(ComponentCounterBinding::inflate) {
down.setOnClickListener { /*...*/ }
up.setOnClickListener { /*...*/ }
}
}
Fragment в Compose
Добавляем FragmentContainerView
в макет XML:
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:name="com.artf.composeinview.ui.main.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Получаем доступ к Fragment
из Compose:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
AndroidViewBinding(ActivityMainBinding::inflate) {
val fragment = container.getFragment<MainFragment>()
//...
}
}
}
}
Заключение
Отбросьте все сомнения и смело начинайте работать с Compose, поскольку в настоящее время API совместимости отлично функционируют. Они позволяют Compose и View сосуществовать в базе кода и предоставляют много преимуществ, включая оптимизацию этапа запуска, размер приложения и время сборки.
Читайте также:
- Интеграция Google Maps в приложение Jetpack Compose
- Как сделать анимированную кнопку загрузки с Jetpack Compose
- Jetpack DataStore: улучшенная система хранения данных
Читайте нас в Telegram, VK и Дзен
Перевод статьи Artur Gniewowski: XML and Jetpack Compose Interoperability