Разработка
10 фич Jetpack Compose, которые изменят ваш подход к разработке Android-приложений
Инструментарий для создания пользовательского интерфейса Android, который, как вам казалось, вы хорошо знаете, таит в себе множество сюрпризов, которые большинство разработчиков упускают из виду.
Вы всё ещё копируете и вставляете один и тот же шаблонный код Compose, который использовали два года назад? Тогда вы разрабатываете медленнее, чем могли бы. В Jetpack Compose незаметно появлялись всё новые и новые фичи, которые снова делают разработку Android UI увлекательной. И знание этих возможностей превращает хорошее приложение в отличное.
Представляем 10 новых вещей, которые стоит внедрить в ваш рабочий процесс уже сегодня.
1. Анимации — профессионально выглядящие переходы с AnimatedContent
Раньше переключения видимости между состояниями UI могли выглядеть немного топорно. AnimatedContent позволяет задавать, как контент появляется и исчезает — затухание, сдвиг, масштабирование, что угодно!
AnimatedContent(
targetState = isLoggedIn,
transitionSpec = {
// Slide in from right, slide out to left
slideInHorizontally { it } togetherWith slideOutHorizontally { -it }
}
) { loggedIn ->
if (loggedIn) HomeScreen() else LoginScreen()
}
Да, переходы имеют значение — пользователи это замечают. Такой уровень проработки вызывает доверие.
2. Не пересоздавайте то, что не изменилось: LazyColumn и key
Большинство разработчиков используют LazyColumn без key. Это нормально — пока вы не измените порядок элементов списка, и тогда каждый элемент начнет мигать и перерисовываться.
Стабильные ключи позволяют Compose более явно понимать, какой элемент есть какой.
LazyColumn {
items(messages, key = { it.id }) { message ->
MessageRow(message)
}
}
3. derivedStateOf — избавьтесь от лишних рекомпозиций
Эту возможность используют редко и часто понимают неправильно. Если у вас есть состояние, зависящее от другого состояния, используйте derivedStateOf — тогда Compose будет выполнять рекомпозицию только при изменении результата, а не каждый раз при изменении исходного состояния.
val showScrollToTop by remember {
derivedStateOf { listState.firstVisibleItemIndex > 3 }
}
Научитесь правильно это использовать: это критически важно для UI-логики, завязанной на прокрутке.
4. Modifier.drawBehind — кастомные фоны без Box
Забудьте о вложенных layout-контейнерах только ради того, чтобы нарисовать собственную форму или градиент. drawBehind даёт вам прямой доступ к Canvas прямо внутри модификатора.
Text(
text = "Hello",
modifier = Modifier.drawBehind {
drawRoundRect(
color = Color(0xFF00D4AA),
cornerRadius = CornerRadius(12f)
)
}
)
5. SubcomposeLayout — измерение размеров дочерних элементов относительно других дочерних элементов.
Принцип, лежащий в основе Scaffold, BoxWithConstraints и наших кастомных систем компоновки, где размер одного компонуемого элемента необходимо измерить перед компоновкой другого, заключается в том, что компонуемые элементы не знают своего собственного размера.
Знание о его существовании обычно является большей частью необходимого — и большинству разработчиков никогда не приходится это писать — но это объясняет, как работают сложные компоновки.
6. Переходы между общими элементами (Compose 1.7+)
Наконец-то. Нативные переходы между общими элементами между компонуемыми элементами без старых процедур системы View.
SharedTransitionLayout {
AnimatedContent(targetState = selected) { isSelected ->
if (isSelected) {
DetailCard(
modifier = Modifier.sharedElement(
rememberSharedContentState("card"),
animatedVisibilityScope = this
)
)
}
}
}
Shared Element Transitions — лучший визуальный способ прокачать сценарий перехода “список → детали”.
7. Pager + HorizontalPager — нативный свайп страниц
HorizontalPager переехал из библиотеки Accompanist в foundation. Эта штука действительно хороша: декларативная, удобная и практически без проблем в использовании. Снэппинг работает именно так, как ожидаешь.
val pagerState = rememberPagerState(pageCount = { tabs.size })
HorizontalPager(state = pagerState) { page ->
TabContent(tab = tabs[page])
}
8. CompositionLocal — секретное оружие против ручной прокидки данных
Не нужно протаскивать цвет темы или пользовательскую сессию через 6 уровней composable-функций. Просто определите CompositionLocal, и сможете читать эти данные где угодно в дереве Compose.
val LocalUserSession = compositionLocalOf<UserSession> { error("No session") }
// Provide at the top
CompositionLocalProvider(LocalUserSession provides session) {
AppContent()
}
// Read anywhere below
val session = LocalUserSession.current
9. Modifier.pointerInput — удобная работа с жестами
Кастомные жесты — двойной тап, долгое нажатие, отслеживание перетаскивания — всё это доступно через pointerInput и API на основе корутин, который действительно, чёрт возьми, нормально работает.
Modifier.pointerInput(Unit) {
detectTapGestures(
onDoubleTap = { viewModel.toggleFavorite() },
onLongPress = { showContextMenu = true }
)
}
10. Система снапшотов — Compose как движок реактивности
Compose построен вокруг реактивной системы, похожей по подходу на React.
Напрямую вы с этим обычно не работаете — но понимание системы делает вас более сильным Compose-разработчиком. Каждый mutableStateOf существует внутри snapshot-системы. Именно поэтому UI остаётся отзывчивым даже тогда, когда изменение состояния сопровождается сложными вычислениями: Compose выполняет чтение и запись состояния пакетно (batch updates), обрабатывая всё за один проход.
Ключевые выводы
- Минимум кода для профессиональных переходов:
AnimatedContent+ shared element transitions - Ваше оружие против лишних рекомпозиций:
derivedStateOf keyв lazy-списках помогает избежать визуальных артефактов при изменении данныхCompositionLocalэлегантно решает проблему prop drilling- Snapshot System — это движок Compose, и наблюдать за его работой довольно просто
Каждый, кто копает чуть глубже, получает награду — Compose действительно поощряет разработчиков за понимание внутренних механизмов. Всё это не какие-то темные хаки, а инструменты, которые команда Compose создала специально для того, чтобы вам не приходилось писать уродливые реализации вручную.
Возьмите хотя бы пару из этих подходов, внедрите их в следующий PR — и вы сразу почувствуете, насколько плавнее и чище станет приложение.
Самый умный Compose-код — не всегда лучший. Лучший Compose-код — это код, написанный осознанно.
