Архитектурное наложение Jetpack Compose

На этой странице представлен общий обзор архитектурных слоев, составляющих Jetpack Compose, а также основные принципы, лежащие в основе этого дизайна.

Jetpack Compose — это не единый монолитный проект; он создается из ряда модулей, которые собираются вместе, образуя полный стек. Понимание различных модулей, составляющих Jetpack Compose, позволит вам:

  • Используйте соответствующий уровень абстракции для создания приложения или библиотеки.
  • Поймите, когда вы можете «спуститься» на более низкий уровень для большего контроля или настройки.
  • Минимизируйте свои зависимости

Слои

Основные уровни Jetpack Compose:

Рисунок 1. Основные уровни Jetpack Compose.

Каждый уровень построен на нижних уровнях, объединяя функциональные возможности для создания компонентов более высокого уровня. Каждый уровень основан на общедоступных API нижних уровней, что позволяет проверять границы модуля и позволяет при необходимости заменить любой уровень. Давайте рассмотрим эти слои снизу вверх.

Время выполнения
Этот модуль предоставляет основы среды выполнения Compose, такие как remember , mutableStateOf , аннотацию @Composable и SideEffect . Вы можете рассмотреть возможность создания непосредственно на этом уровне, если вам нужны только возможности управления деревом Compose, а не его пользовательский интерфейс.
пользовательский интерфейс
Уровень пользовательского интерфейса состоит из нескольких модулей ( ui-text , ui-graphics , ui-tooling и т. д.). Эти модули реализуют основы набора инструментов пользовательского интерфейса, такие как LayoutNode , Modifier , обработчики ввода, пользовательские макеты и рисование. Вы можете рассмотреть возможность использования этого уровня, если вам нужны только фундаментальные концепции набора инструментов пользовательского интерфейса.
Фундамент
Этот модуль предоставляет независимые от системы дизайна строительные блоки для пользовательского интерфейса Compose, такие как Row и Column , LazyColumn , распознавание определенных жестов и т. д. Вы можете рассмотреть возможность использования базового уровня для создания собственной системы дизайна.
Материал
Этот модуль обеспечивает реализацию системы Material Design для пользовательского интерфейса Compose, предоставляя систему тем, стилизованные компоненты, индикаторы пульсации, значки. Используйте этот уровень при использовании Material Design в своем приложении.

Принципы дизайна

Руководящим принципом Jetpack Compose является предоставление небольших, сфокусированных частей функциональности, которые можно собрать (или скомпоновать) вместе, а не нескольких монолитных компонентов. Этот подход имеет ряд преимуществ.

Контроль

Компоненты более высокого уровня, как правило, делают больше для вас, но ограничивают объем вашего прямого контроля. Если вам нужно больше контроля, вы можете «спуститься вниз», чтобы использовать компонент более низкого уровня.

Например, если вы хотите анимировать цвет компонента, вы можете использовать API animateColorAsState :

val color = animateColorAsState(if (condition) Color.Green else Color.Red)

Однако если вам нужно, чтобы компонент всегда начинался серым, вы не сможете сделать это с помощью этого API. Вместо этого вы можете перейти к использованию Animatable API нижнего уровня:

val color = remember { Animatable(Color.Gray) }
LaunchedEffect(condition) {
    color.animateTo(if (condition) Color.Green else Color.Red)
}

API animateColorAsState более высокого уровня сам по себе построен на API Animatable более низкого уровня. Использование API нижнего уровня более сложное, но предлагает больше контроля. Выберите уровень абстракции, который лучше всего соответствует вашим потребностям.

Кастомизация

Сборка компонентов более высокого уровня из более мелких строительных блоков значительно упрощает настройку компонентов в случае необходимости. Например, рассмотрим реализацию Button , предоставляемую слоем материала:

@Composable
fun Button(
    // …
    content: @Composable RowScope.() -> Unit
) {
    Surface(/* … */) {
        CompositionLocalProvider(/* … */) { // set LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                Row(
                    // …
                    content = content
                )
            }
        }
    }
}

Button собирается из 4-х компонентов:

  1. Материальная Surface обеспечивающая фон, форму, обработку щелчков и т. д.

  2. CompositionLocalProvider , который изменяет альфа-канал содержимого, когда кнопка включена или отключена.

  3. ProvideTextStyle устанавливает стиль текста по умолчанию, который будет использоваться.

  4. Row предоставляет политику макета по умолчанию для содержимого кнопки.

Мы опустили некоторые параметры и комментарии, чтобы сделать структуру более понятной, но весь компонент занимает всего около 40 строк кода, поскольку он просто собирает эти 4 компонента для реализации кнопки. Такие компоненты, как Button имеют самоуверенность в отношении того, какие параметры они предоставляют, балансируя между возможностью общих настроек и взрывным ростом параметров, которые могут затруднить использование компонента. Например, компоненты материалов предлагают настройки, указанные в системе Material Design, что позволяет легко следовать принципам проектирования материалов.

Однако если вы хотите выполнить настройку, выходящую за рамки параметров компонента, вы можете «спуститься» на уровень и разветвить компонент. Например, Material Design требует, чтобы кнопки имели однотонный фон. Если вам нужен градиентный фон, этот параметр не поддерживается параметрами Button . В этом случае вы можете использовать реализацию Material Button в качестве образца и создать свой собственный компонент:

@Composable
fun GradientButton(
    // …
    background: List<Color>,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(
                Brush.horizontalGradient(background)
            )
    ) {
        CompositionLocalProvider(/* … */) { // set material LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                content()
            }
        }
    }
}

Вышеупомянутая реализация продолжает использовать компоненты из слоя Материала, такие как концепции Материала о текущей альфе контента и текущем текстовом стиле. Однако он заменяет материал Surface на Row и стилизует его для достижения желаемого внешнего вида.

Если вы вообще не хотите использовать концепции материалов, например, при создании собственной индивидуальной системы дизайна, вы можете перейти к чистому использованию компонентов базового слоя:

@Composable
fun BespokeButton(
    // …
    backgroundColor: Color,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(backgroundColor)
    ) {
        // No Material components used
        content()
    }
}

Jetpack Compose резервирует самые простые имена для компонентов самого высокого уровня. Например, androidx.compose.material.Text построен на основе androidx.compose.foundation.text.BasicText . Это позволяет предоставить вашей собственной реализации наиболее доступное имя, если вы хотите заменить более высокие уровни.

Правильный выбор абстракции

Философия Compose по созданию многоуровневых, многократно используемых компонентов означает, что вам не всегда следует обращаться к строительным блокам нижнего уровня. Многие компоненты более высокого уровня не только предлагают больше функциональности, но и часто реализуют лучшие практики, такие как поддержка специальных возможностей.

Например, если вы хотите добавить поддержку жестов в свой пользовательский компонент, вы можете создать его с нуля, используя Modifier.pointerInput , но на его основе созданы другие компоненты более высокого уровня, которые могут стать лучшей отправной точкой, например Modifier.draggable , Modifier.scrollable или Modifier.swipeable .

Как правило, предпочитают создавать компоненты самого высокого уровня , которые предлагают необходимую вам функциональность, чтобы извлечь выгоду из лучших практик, которые они включают.

Узнать больше

См. пример Jetsnack для примера создания системы индивидуального проектирования.

{% дословно %} {% дословно %} {% дословно %} {% дословно %}