-
Jetpack Compose — это современный инструментарий для создания интерфейсов на языке Kotlin в приложениях Android. Он был разработан командой Google для упрощения и ускорения процесса разработки интерфейсов, сделав его более декларативным и интуитивно понятным. В отличие от традиционного подхода с использованием XML для разметки интерфейсов, Jetpack Compose позволяет разработчикам строить интерфейс напрямую в коде, используя Kotlin.
-
- Composition: На этом этапе Compose строит или обновляет дерево компонентов UI, основываясь на текущем состоянии приложения. Компоненты (Composables) описывают, какие UI элементы должны быть отображены.
- Layout: После составления дерева UI, система определяет размеры и позиционирование каждого элемента на экране. Это включает расчёт размеров в соответствии с ограничениями родительских элементов и расположение дочерних элементов.
- Draw: На последнем этапе Compose отрисовывает UI на экране. Это включает в себя рисование текста, фигур, изображений и других визуальных элементов.

-
Composable функция в Jetpack Compose — это специальный тип функции, аннотированный с @Composable. Эти функции являются строительными блоками пользовательского интерфейса в Compose и используются для описания, как должен выглядеть и функционировать UI. В отличие от традиционных функций, composable функции могут содержать другие composable вызовы, позволяя создавать сложный и динамичный интерфейс путем комбинирования более мелких, повторно используемых компонентов.
-
В общем случае, composable функции предназначены для вызова только из других composable функций. Это связано с тем, что они используют специальный контекст композиции, который управляет их жизненным циклом, состоянием и оптимизацией перекомпозиции. Попытка вызвать composable функцию вне контекста композиции (например, из обычной функции Kotlin или из функции активити) приведет к ошибке компиляции.
Это ограничение обусловлено тем, как работает система композиции в Jetpack Compose. Когда composable функция вызывается, она регистрирует себя и свои параметры в текущем контексте композиции, что позволяет системе Compose отслеживать зависимости и определять, когда и какие части UI нужно перерисовать. Без этого контекста композиции система не сможет корректно управлять жизненным циклом composable функций, их состоянием и оптимизацией перекомпозиции. -
- remember: Это функция, используемая в Compose для сохранения состояния во время перекомпозиции. Когда параметры функции remember изменяются, она сбрасывает и пересоздаёт состояние с новыми значениями. Это полезно для сохранения объектов или значений, которые должны сохраняться между перекомпозициями, но не нуждаются в сохранении через процессы пересоздания активити или фрагмента.
- rememberSaveable: Расширяет возможности remember, позволяя сохранять простые данные через процессы пересоздания активити или фрагмента, например, при повороте экрана. rememberSaveable использует механизм сохранения состояния в Bundle и подходит для примитивных типов данных и некоторых стандартных типов, таких как String.
Чтобы использовать сохранение объектов, то необходимо пометить класс как Parcelize или использовать MapSaver, ListSaver.
-
mutableStateOf - это функция, создающая объект состояния, который может быть изменяемым. Этот объект реализует паттерн наблюдателя, так что Compose может автоматически отслеживать изменения этого состояния и перерисовывать UI компоненты, которые зависят от этого состояния. mutableStateOf идеально подходит для управления состояниями в Compose, так как обеспечивает реактивное обновление UI.
-
- derivedStateOf - эта функция используется для создания производного состояния, значение которого вычисляется на основе других состояний. derivedStateOf предоставляет оптимизированный способ отслеживания изменений, так как Compose будет перерисовывать UI только тогда, когда действительно изменится производное значение, а не каждый раз при изменении исходных состояний.
- mutableStateOf предназначен для хранения изменяемых данных и уведомления Compose о необходимости перерисовки при их изменении. Он является основой для управления состоянием в Compose.
- В отличие от mutableStateOf, derivedStateOf не хранит изменяемые данные, а предоставляет механизм для создания значения, зависящего от одного или нескольких других состояний, оптимизируя при этом процесс перерисовки.
-
Recomposition — это процесс, в ходе которого Compose автоматически перерисовывает UI компоненты при изменении состояния, от которого они зависят. Это ключевой аспект реактивного подхода к построению интерфейса в Compose, позволяющий UI динамически адаптироваться к изменениям данных. Во время перекомпозиции Compose оптимизированно обновляет только те части интерфейса, которые действительно изменились, что делает процесс быстрым и эффективным.
Recomposition активизируется изменениями в объектах состояния (например, значениях, обернутых в mutableStateOf), и Compose следит за этими изменениями, автоматически запуская перекомпозицию для затронутых компонентов. Это обеспечивает актуальность отображаемых данных и визуальных элементов -
State hoisting (подъем состояния) — это паттерн проектирования в Jetpack Compose, который рекомендуется для управления состоянием UI компонентов. Суть паттерна заключается в перемещении (или "подъеме") состояния из компонента (composable функции) на более высокий уровень в иерархии, чтобы сделать компонент более декларативным и упростить повторное использование и тестирование.
При использовании подъема состояния компонент принимает текущее состояние и функции для изменения этого состояния через свои параметры, вместо того чтобы самостоятельно их создавать и управлять ими. Это означает, что состояние хранится вне компонента и передается в него, делая компонент более универсальным и предсказуемым. -
- DisposableEffect используется для управления ресурсами, которые требуют очистки при изменении ключей или при удалении композиции из UI дерева. Это может включать отписку от подписок, остановку анимации или закрытие соединений.
- LaunchedEffect запускает корутину в контексте жизненного цикла композиции. Он полезен для выполнения асинхронных операций, таких как загрузка данных с сервера, при сохранении синхронизации с жизненным циклом Composable.
- rememberCoroutineScope предоставляет доступ к CoroutineScope для запуска корутин в контексте текущей композиции, позволяя выполнять асинхронные операции с возможностью отмены и без привязки к жизненному циклу композиции.
- rememberUpdatedState позволяет "запомнить" самое последнее значение передаваемого состояния или колбэка, так что даже если асинхронная операция завершилась после того, как состояние было изменено, используется актуальное значение.
- produceState используется для создания состояния в Composable, которое может быть асинхронно обновлено. Оно идеально подходит для инкапсуляции асинхронной логики загрузки данных непосредственно в состоянии.
- derivedStateOf используется для создания состояния, которое вычисляется на основе других состояний. Это помогает оптимизировать перерисовку, так как Compose будет перерисовывать UI только при изменении результата вычисления.
- SideEffect используется для выполнения побочных эффектов, которые должны запускаться при каждой перекомпозиции, но не требуют очистки или отмены. Это может быть полезно для обновления заголовка экрана, логирования и т.д.
-
Modifier является ключевым концептом, который позволяет вам изменять или дополнять поведение компонентов (Composables) без изменения их кода. Это мощный инструмент для реализации таких вещей, как стилизация, расположение и обработка событий ввода.
Основные аспекты Modifier:- Цепочечная природа: Modifiers могут быть соединены в цепочку, позволяя применять несколько модификаций последовательно. Каждый модификатор в цепочке вносит свой вклад, изменяя или дополняя предыдущие.
- Повторное использование: Modifiers могут быть определены один раз и повторно использованы в разных компонентах, способствуя сокращению дублирования кода и улучшению его читаемости.
- Расширяемость: Система Modifier в Compose предоставляет большое количество встроенных модификаторов, но также позволяет создавать собственные, что делает ее крайне гибкой и мощной.
-
Темы в Jetpack Compose позволяют вам управлять визуальной консистентностью вашего приложения на высоком уровне, определяя цвета, типографику и другие аспекты дизайна, которые могут быть использованы по всему приложению
-
В Jetpack Compose, система Layout позволяет разработчикам определять, как UI компоненты должны быть размещены и отображены на экране. Это включает в себя расположение элементов (как они позиционируются относительно друг друга), их размеры и пространство между ними. Compose предлагает гибкую систему Layout, которая может быть адаптирована под различные потребности дизайна.
Ключевые аспекты:- Модификаторы для управления макетом: padding, size, fillMaxSize, и др.
- Встроенные контейнеры макета: Column, Row, Box, и ConstraintLayout для сложных макетов.
- Пользовательские макеты: Создание собственных макетных контейнеров с использованием низкоуровневых API для полного контроля над расположением и рендерингом.
-
Для отображения списков данных, Compose предлагает LazyColumn и LazyRow, которые аналогичны RecyclerView в классическом Android UI Toolkit. Эти компоненты лениво отображают элементы, т.е., рендерят только те элементы, которые видны на экране, что делает их высокоэффективными для отображения больших списков.
Ключевые аспекты:- Эффективность: Ленивая загрузка элементов улучшает производительность при работе с большими объемами данных.
- Гибкость: Поддержка горизонтального и вертикального скроллинга, вложенных списков и динамически изменяемых элементов.
- Пользовательские элементы: Возможность создавать сложные и настраиваемые элементы списка.
-
Обработка жестов в Compose позволяет реагировать на различные пользовательские взаимодействия, такие как касания, свайпы, длительные нажатия и многое другое. Compose предоставляет удобные модификаторы и API для интеграции жестов в компоненты UI.
Ключевые аспекты:- Модификаторы для обработки жестов: clickable, onLongPress, swipeable, и т.д.
- Интеграция с анимациями: Жесты могут быть легко интегрированы с анимационными эффектами для создания плавных и отзывчивых интерактивных элементов.
-
Система анимации в Jetpack Compose предлагает мощные и гибкие инструменты для добавления анимаций в ваше приложение. Анимации могут быть простыми, как изменение цвета кнопки, так и сложными, как сложные переходы и трансформации.
Ключевые аспекты:- Анимированные состояния: Использование animate*AsState для создания анимированных переходов между состояниями.
- Переходные анимации: AnimatedVisibility и updateTransition для управления сложными анимациями с несколькими свойствами.
- Низкоуровневые API: Для полного контроля над анимационным процессом.
-
CompositionLocal предоставляет механизм для передачи данных вниз по дереву композиции без необходимости явно передавать пропсы через каждый уровень вложенности. Это полезно для доступа к общим данным, таким как темы, локализация или доступ к данным окружения.
Ключевые аспекты:- Избегание prop drilling: Упрощает передачу данных в глубоко вложенные компоненты.
- Доступ к данным окружения: Идеально подходит для тем, локализации и других настроек, которые должны быть доступны во всем приложении.
- Пользовательские CompositionLocal: Возможность создания собственных объектов CompositionLocal для управления специфичными для приложения данными.
-
-
Row. Горизонтальный контейнер, размещает элементы в одну строку.
Row( horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically ) { Text("A") Text("B") Text("C") }
-
Column. Вертикальный контейнер, размещает элементы сверху вниз.
Column( verticalArrangement = Arrangement.spacedBy(8.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text("Item 1") Text("Item 2") Text("Item 3") }
-
Box. Наложение элементов друг на друга, управление позиционированием через
Modifier.align.Box(Modifier.size(100.dp)) { Text("Bottom", Modifier.align(Alignment.BottomEnd)) Text("Top", Modifier.align(Alignment.TopStart)) }
-
Spacer. Пустой элемент для отступов или разделения.
Column { Text("Top") Spacer(Modifier.height(16.dp)) Text("Bottom") }
-
-
BoxWithConstraints. Как
Box, но предоставляет доступ кmaxWidth,maxHeightи другим ограничениям. Позволяет адаптировать контент под доступное место.@Composable fun AdaptiveCard() = BoxWithConstraints { if (maxWidth < 400.dp) CompactCard() else WideCard() }
-
- FlowRow / FlowColumn. Автоматически переносят элементы на новую строку или колонку при нехватке места.
@OptIn(ExperimentalLayoutApi::class) @Composable fun Chips(tags: List<String>) { FlowRow( horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { tags.forEach { Text(it, Modifier.background(Color.LightGray).padding(4.dp)) } } }
- FlowRow / FlowColumn. Автоматически переносят элементы на новую строку или колонку при нехватке места.
-
-
LazyColumn. Вертикальный список с ленивой и умной подгрузкой элементов.
@Composable fun MessagesList(messages: List<String>) { LazyColumn( verticalArrangement = Arrangement.spacedBy(8.dp), contentPadding = PaddingValues(16.dp) ) { items(messages) { msg -> Text(msg) } } }
-
LazyRow. Горизонтальный список с ленивой и умной подгрузкой элементов.
LazyRow(horizontalArrangement = Arrangement.spacedBy(8.dp)) { items(10) { index -> Text("Item $index") } }
-
LazyVerticalGrid. Ленивый грид по вертикали.
LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 120.dp), contentPadding = PaddingValues(8.dp) ) { items(20) { i -> Box(Modifier.size(100.dp).background(Color.Gray)) { Text("$i") } } }
-
LazyHorizontalGrid. Аналогичный грид, но по горизонтали.
LazyHorizontalGrid(rows = GridCells.Fixed(2)) { items(10) { i -> Text("Item $i") } }
-
ConstraintLayout. Позволяет задавать связи между элементами и родителем, создавать гибкие интерфейсы.
Возможно, что устарел и использовать его крайне не рекомендуется, из-за того, что обход дерева происходит дважды.
@Composable fun Header() { ConstraintLayout { val (avatar, name, button) = createRefs() Image( painterResource(id = R.drawable.ic_avatar), null, Modifier.size(48.dp).constrainAs(avatar) { start.linkTo(parent.start) top.linkTo(parent.top) } ) Text("Ada Lovelace", Modifier.constrainAs(name) { start.linkTo(avatar.end, margin = 8.dp) centerVerticallyTo(avatar) }) Button(onClick = {}, Modifier.constrainAs(button) { end.linkTo(parent.end) centerVerticallyTo(avatar) }) { Text("Follow") } } }
-
-
Информация может быть неточной или неполной. Какой-то код может устареть
-
Layout. Позволяет реализовать собственную стратегию измерения и позиционирования.
@Composable fun OverlapLayout(overlap: Dp = 16.dp, content: @Composable () -> Unit) = Layout(content = content) { measurables, constraints -> val placeables = measurables.map { it.measure(constraints) } val width = placeables.sumOf { it.width } - overlap.roundToPx() * (placeables.size - 1) val height = placeables.maxOfOrNull { it.height } ?: 0 layout(width, height) { var x = 0 placeables.forEach { it.placeRelative(x, 0) x += it.width - overlap.roundToPx() } } }
-
SubcomposeLayout. Позволяет сабкомпозировать дочерние элементы во время измерения. Используется, если контент одного блока зависит от размеров другого.
@Composable fun BadgeLayout(main: @Composable () -> Unit, badge: @Composable (IntSize) -> Unit) { SubcomposeLayout { constraints -> val mainPlaceables = subcompose("main", main).map { it.measure(constraints) } val size = IntSize( width = mainPlaceables.maxOf { it.width }, height = mainPlaceables.maxOf { it.height } ) val badgePlaceables = subcompose("badge") { badge(size) }.map { it.measure(Constraints()) } layout(size.width, size.height) { mainPlaceables.forEach { it.placeRelative(0, 0) } badgePlaceables.forEach { it.placeRelative(size.width - it.width, 0) } } } }
-