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

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

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

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

Слои

Основные слои Jetpack Compose:

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

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

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

Принципы проектирования

Основной принцип Jetpack Compose — предоставление небольших, целенаправленных функциональных возможностей, которые можно объединять (или комбинировать) друг с другом, а не нескольких монолитных компонентов. Такой подход имеет ряд преимуществ.

Контроль

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

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

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

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

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

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

Настройка

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

@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, что упрощает следование принципам 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()
            }
        }
    }
}

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

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

@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 .

{% verbatim %} {% endverbatim %} {% verbatim %} {% endverbatim %}