There are several ways you can build out your apps using Styles. What you choose depends on where your app sits in relation to its adoption of Material Design:
- Полностью индивидуальная система дизайна, не использующая Material Design.
- Рекомендация : Определите стили компонентов, которые используют значения из темы оформления, и предоставьте доступ к параметрам стиля для компонентов системы дизайна.
- Использование Material Design
- Рекомендация : Дождитесь внедрения Material Design для интеграции со стилями. По возможности используйте стили в собственных компонентах.
Слой стиля
В традиционной модели Compose настройка часто в значительной степени опирается на переопределение глобальных токенов (цветов и типографики), предоставляемых MaterialTheme , или на обертывание и переопределение свойств системы дизайна, которую можно комбинировать, где это возможно. Иногда в слое Material есть свойства, которые не отображаются через подсистемы или параметры, а являются жестко заданными значениями по умолчанию для самого компонента.
API стилей (Styles API) представляет собой новый уровень абстракции, служащий мостом между подсистемами и компонентами: стили .
| Слой | Ответственность | Пример |
|---|---|---|
| Значения подсистем | Именованные значения | val Primary = Color(0xFF34A85E) |
| Атомные стили | Стиль, который вносит ровно одно изменение в свойство. | val buttonStyle = paddingAtomic then roundedCornerShapeAtomic then primaryBackgroundAtomic then largeSize then interactiveShadowAtomic |
| Стили компонентов | Конфигурации, специфичные для компонентов | Кнопка с основным фоном и отступом 16dp. val buttonStyle = Style { contentPadding(16.dp) shape(RoundedCornerShape(8.dp)) background(Color.Blue) } |
| Компоненты | Функциональный элемент пользовательского интерфейса, который использует стиль. | Button(style = buttonStyle) { ... } |

Атомарный против монолитного стиля
С помощью Styles API вы можете разбить стиль на отдельные атомарные стили. Вместо определения сложных, специфичных для компонентов стилей, таких как baseButtonStyle , вы также можете создавать небольшие, узкоспециализированные вспомогательные стили. Они выступают в роли ваших «атомов».
// Define single-purpose "atomic" styles val paddingAtomic = Style { contentPadding(16.dp) } val roundedCornerShapeAtomic = Style { shape(RoundedCornerShape(8.dp)) } val primaryBackgroundAtomic = Style { background(Color.Blue) } val largeSizeAtomic = Style { size(100.dp, 40.dp) } val interactiveShadowAtomic = Style { hovered { animate { dropShadow( Shadow( offset = DpOffset( 0.dp, 0.dp ), radius = 2.dp, spread = 0.dp, color = Color.Blue, ) ) } } }
Композиция с использованием слова «затем»
Одна из мощных функций нового API стилей — это оператор then , который позволяет объединять несколько объектов Style . Это позволяет создавать компоненты, используя атомарные вспомогательные классы.
Традиционный (неатомный) :
// One large monolithic style val buttonStyle = Style { contentPadding(16.dp) shape(RoundedCornerShape(8.dp)) background(Color.Blue) }
Атомарный рефакторинг :
// Combine atoms to create the final appearance val buttonStyle = paddingAtomic then roundedCornerShapeAtomic then primaryBackgroundAtomic then interactiveShadowAtomic
Внедрите стили в свою систему дизайна.
При внедрении стилей в вашу дизайн-систему следует учитывать следующие варианты, в зависимости от того, на каком этапе развития находится ваша дизайн-система.
Система индивидуального дизайна со стилями.
Подумайте, когда : вам передали обширное руководство по фирменному стилю, которое не основано на Material Design, и вы не планируете использовать Material Design .
Стратегия : Внедрить полностью настраиваемую систему дизайна и сделать стили доступными в рамках темы оформления .
Этот вариант является пользовательским, если вы не используете Material в качестве основного языка дизайна. Вы полностью обходите MaterialTheme для определения визуальных параметров и уже создали свою собственную пользовательскую тему . Вы создаете CompanyTheme , которая выступает в качестве контейнера для ваших стилей.
- Как это работает : Создайте объект
CompanyTheme, который содержит объектыStyleдля каждого компонента в вашей системе. Ваши компоненты (будь то обертки над логикой Material или пользовательские реализацииBoxилиLayout) напрямую используют эти стили и предоставляют параметрStyleдля пользователей вашей системы дизайна. - Слой стилей : Стили — это основное определение вашей системы дизайна. Токены — это именованные переменные, передаваемые в эти стили. Это позволяет осуществлять глубокую настройку, например, определять уникальные анимации для изменений состояния (например, анимация масштабирования и цвета при нажатии).
Если вы создаёте собственную пользовательскую тему без использования Material Design и хотите применить стили, добавьте список стилей в свою тему. Это позволит вам получить доступ к базовым стилям из любой точки вашего проекта.
Создайте класс
Styles, который будет хранить различные стили в вашем приложении, и задайте для них значения по умолчанию. Например, в приложении Jetsnack этот класс называетсяJetsnackStyles:object JetsnackStyles{ val buttonStyle: Style = Style { shape(shapes.medium) background(colors.brand) contentColor(colors.textPrimary) contentPaddingVertical(8.dp) contentPaddingHorizontal(24.dp) textStyle(typography.labelLarge) disabled { animate { background(colors.brandSecondary) } } } val cardStyle: Style = Style { shape(shapes.medium) background(colors.uiBackground) contentColor(colors.textPrimary) } }
Включите
Stylesв общую тему оформления и предоставьте вспомогательные функции расширения вStyleScopeдля доступа к подсистемам:@Immutable class JetsnackTheme( val colors: JetsnackColors = LightJetsnackColors, val typography: androidx.compose.material3.Typography = androidx.compose.material3.Typography(), val shapes: Shapes = Shapes() ) { companion object { val colors: JetsnackColors @Composable @ReadOnlyComposable get() = LocalJetsnackTheme.current.colors val typography: androidx.compose.material3.Typography @Composable @ReadOnlyComposable get() = LocalJetsnackTheme.current.typography val shapes: Shapes @Composable @ReadOnlyComposable get() = LocalJetsnackTheme.current.shapes val styles: JetsnackStyles = JetsnackStyles val LocalJetsnackTheme: ProvidableCompositionLocal<JetsnackTheme> get() = LocalJetsnackThemeInstance } } val StyleScope.colors: JetsnackColors get() = LocalJetsnackTheme.currentValue.colors val StyleScope.typography: androidx.compose.material3.Typography get() = LocalJetsnackTheme.currentValue.typography val StyleScope.shapes: Shapes get() = LocalJetsnackTheme.currentValue.shapes internal val LocalJetsnackThemeInstance = staticCompositionLocalOf { JetsnackTheme() } @Composable fun JetsnackTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { val colors = if (darkTheme) DarkJetsnackColors else LightJetsnackColors val theme = JetsnackTheme(colors = colors) CompositionLocalProvider( LocalJetsnackTheme provides theme, ) { MaterialTheme( typography = LocalJetsnackTheme.current.typography, shapes = LocalJetsnackTheme.current.shapes, content = content, ) } }
Получите доступ к
JetsnackStylesвнутри вашего составного приложения:@Composable fun CustomButton(modifier: Modifier, style: Style = Style, text: String) { val interactionSource = remember { MutableInteractionSource() } val styleState = remember(interactionSource) { MutableStyleState(interactionSource) } // Apply style to top level container in combination with incoming style from parameter. Box(modifier = modifier .clickable( interactionSource = interactionSource, indication = null, enabled = true, role = Role.Button, onClick = { }, ) .styleable(styleState, JetsnackTheme.styles.buttonStyle, style)) { Text(text) } }
Помимо глобального внедрения тем оформления, существуют альтернативные стратегии интеграции Styles в ваши приложения. Вы можете использовать Styles непосредственно в коде для конкретных мест вызовов или использовать статические определения, когда полные возможности оформления не требуются. Styles не следует менять условно, если только весь стиль принципиально не отличается. Предпочтительнее использовать динамические токены внутри определения визуального элемента, а не переключаться между различными объектами стиля.