Jetpack Compose предлагает реализацию Material Design — комплексной системы дизайна для создания цифровых интерфейсов. Компоненты Material Design (кнопки, карточки, переключатели и т. д.) построены на основе Material Theming — системного способа настройки Material Design для лучшего соответствия бренду вашего продукта. Material Theme включает атрибуты цвета , типографики и формы . При настройке этих атрибутов изменения автоматически отражаются в компонентах, используемых для создания вашего приложения.
Jetpack Compose реализует эти концепции с помощью компонуемого MaterialTheme :
MaterialTheme( colors = // ... typography = // ... shapes = // ... ) { // app content }
Настройте параметры, передаваемые в MaterialTheme для оформления темы вашего приложения.

Цвет
Цвета моделируются в Compose с помощью класса Color — класса хранения данных.
val Red = Color(0xffff0000) val Blue = Color(red = 0f, green = 0f, blue = 1f)
Хотя вы можете организовать их как угодно (как константы верхнего уровня, в рамках синглтона или определить их как встроенные), мы настоятельно рекомендуем указывать цвета в теме и извлекать их оттуда. Такой подход позволяет поддерживать тёмную тему и вложенные темы.

Compose предоставляет класс Colors для моделирования цветовой системы Material . Colors предоставляет функции-конструкторы для создания наборов светлых и тёмных цветов:
private val Yellow200 = Color(0xffffeb46) private val Blue200 = Color(0xff91a4fc) // ... private val DarkColors = darkColors( primary = Yellow200, secondary = Blue200, // ... ) private val LightColors = lightColors( primary = Yellow500, primaryVariant = Yellow400, secondary = Blue700, // ... )
После того, как вы определили свои Colors , вы можете передать их в MaterialTheme :
MaterialTheme( colors = if (darkTheme) DarkColors else LightColors ) { // app content }
Использовать цвета темы
Вы можете получить Colors , предоставленные для компоновки MaterialTheme , с помощью MaterialTheme.colors .
Text( text = "Hello theming", color = MaterialTheme.colors.primary )
Цвет поверхности и содержимого
Многие компоненты принимают пару цвет-цвет содержимого:
Surface( color = MaterialTheme.colors.surface, contentColor = contentColorFor(color), // ... ) { /* ... */ } TopAppBar( backgroundColor = MaterialTheme.colors.primarySurface, contentColor = contentColorFor(backgroundColor), // ... ) { /* ... */ }
Это позволяет не только задать цвет компонуемого элемента, но и задать цвет по умолчанию для его содержимого, то есть для всех его компонуемых элементов. Многие компонуемые элементы используют этот цвет по умолчанию. Например, цвет элемента Text зависит от цвета родительского элемента, а Icon использует этот цвет для установки оттенка.

Метод contentColorFor() извлекает соответствующий цвет «включения» для любых цветов темы. Например, если вы задаёте primary цвет фона на Surface , эта функция использует onPrimary в качестве цвета контента. Если вы задаёте цвет фона, не относящийся к теме, необходимо также указать соответствующий цвет контента. Используйте LocalContentColor для получения предпочтительного цвета контента для текущего фона в заданной позиции в иерархии.
Контент альфа
Часто требуется варьировать степень выделения контента, чтобы подчеркнуть его важность и обеспечить визуальную иерархию. Рекомендации по читаемости текста в стиле Material Design рекомендуют использовать разные уровни прозрачности для передачи разной степени важности.
Jetpack Compose реализует это с помощью LocalContentAlpha . Вы можете указать альфа-канал содержимого для иерархии, указав значение CompositionLocal . Вложенные компонуемые элементы могут использовать это значение для применения альфа-обработки к своему содержимому. Например, Text и Icon по умолчанию используют комбинацию LocalContentColor настроенную на использование LocalContentAlpha . Material определяет некоторые стандартные значения альфа-канала ( high , medium , disabled ), которые моделируются объектом ContentAlpha .
// By default, both Icon & Text use the combination of LocalContentColor & // LocalContentAlpha. De-emphasize content by setting content alpha CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text( // ... ) } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Icon( // ... ) Text( // ... ) }
Дополнительную информацию о CompositionLocal см. в статье Локально определяемые данные с помощью CompositionLocal .

ContentAlpha.high . Вторая строка содержит менее важные метаданные и поэтому использует ContentAlpha.medium .Темная тема
В Compose вы реализуете светлые и темные темы, предоставляя различные наборы Colors для компонуемого элемента MaterialTheme :
@Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColors else LightColors, /*...*/ content = content ) }
В этом примере MaterialTheme обёрнут в собственную компонуемую функцию, которая принимает параметр, указывающий, использовать тёмную тему или нет. В этом случае функция получает значение по умолчанию для darkTheme , запрашивая настройку темы устройства .
Вы можете использовать такой код, чтобы проверить, являются ли текущие Colors светлыми или темными:
val isLightTheme = MaterialTheme.colors.isLight Icon( painterResource( id = if (isLightTheme) { R.drawable.ic_sun_24 } else { R.drawable.ic_moon_24 } ), contentDescription = "Theme" )
Наложения высот
В Material поверхности в тёмных темах с более высокими уровнями рельефа получают наложения рельефа , которые осветляют их фон. Чем выше уровень рельефа поверхности (то есть она ближе к предполагаемому источнику света), тем светлее она становится.
Компонуемый объект Surface автоматически применяет эти наложения при использовании темных цветов, как и любой другой компонуемый объект Material, использующий поверхность:
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }

surface в качестве фона. Поскольку карточки и нижняя панель навигации находятся на разной высоте над фоном, их цвета немного различаются: карточки светлее фона, а нижняя панель навигации светлее карточек. Для пользовательских сценариев, не включающих Surface , используйте LocalElevationOverlay — CompositionLocal , содержащий ElevationOverlay используемый компонентами Surface :
// Elevation overlays // Implemented in Surface (and any components that use it) val color = MaterialTheme.colors.surface val elevation = 4.dp val overlaidColor = LocalElevationOverlay.current?.apply( color, elevation )
Чтобы отключить наложения высот, укажите null в выбранной точке в компонуемой иерархии:
MyTheme { CompositionLocalProvider(LocalElevationOverlay provides null) { // Content without elevation overlays } }
Ограниченные цветовые акценты
Material рекомендует использовать ограниченное количество цветовых акцентов для тёмных тем, в большинстве случаев отдавая предпочтение цвету surface , а не primary цвету. Компонуемые элементы Material, такие как TopAppBar и BottomNavigation реализуют это поведение по умолчанию.

Для пользовательских сценариев используйте свойство расширения primarySurface :
Surface( // Switches between primary in light theme and surface in dark theme color = MaterialTheme.colors.primarySurface, /*...*/ ) { /*...*/ }
Типографика
Material определяет систему типов , поощряя использование небольшого количества семантически именованных стилей.

Compose реализует систему типов с помощью классов Typography , TextStyle и классов, связанных со шрифтами . Конструктор Typography предлагает значения по умолчанию для каждого стиля, так что вы можете исключить те, которые не хотите настраивать:
val raleway = FontFamily( Font(R.font.raleway_regular), Font(R.font.raleway_medium, FontWeight.W500), Font(R.font.raleway_semibold, FontWeight.SemiBold) ) val myTypography = Typography( h1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W300, fontSize = 96.sp ), body1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W600, fontSize = 16.sp ) /*...*/ ) MaterialTheme(typography = myTypography, /*...*/) { /*...*/ }
Если вы хотите использовать везде один и тот же шрифт, укажите параметр defaultFontFamily и опустите fontFamily всех элементов TextStyle :
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
Использовать стили текста
Доступ к элементам TextStyle осуществляется через MaterialTheme.typography . Получить элементы TextStyle можно следующим образом:
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )

Форма
Материал определяет систему форм , позволяя вам определять формы для больших, средних и малых компонентов.

Compose реализует систему фигур с классом Shapes , который позволяет указать CornerBasedShape для каждой категории размеров:
val shapes = Shapes( small = RoundedCornerShape(percent = 50), medium = RoundedCornerShape(0f), large = CutCornerShape( topStart = 16.dp, topEnd = 0.dp, bottomEnd = 0.dp, bottomStart = 16.dp ) ) MaterialTheme(shapes = shapes, /*...*/) { /*...*/ }
Многие компоненты используют эти формы по умолчанию. Например, Button , TextField и FloatingActionButton по умолчанию имеют малый размер, AlertDialog — средний, а ModalDrawer — большой. Полное сопоставление см. в справочнике схем форм .
Используйте формы
Доступ к элементам Shape осуществляется с помощью MaterialTheme.shapes . Для получения элементов Shape используйте следующий код:
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }

Стили по умолчанию
В Compose нет эквивалентной концепции стилей по умолчанию из Android Views. Вы можете реализовать аналогичную функциональность, создав собственные overload компонуемые функции, которые обёртывают компоненты Material. Например, чтобы создать стиль кнопки, оберните кнопку в собственную компонуемую функцию, напрямую задав параметры, которые нужно изменить, и предоставив остальные в качестве параметров для компонуемого объекта.
@Composable fun MyButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary ), onClick = onClick, modifier = modifier, content = content ) }
Тематические наложения
Вы можете добиться эквивалента наложений темы из Android Views в Compose, вложив компонуемые элементы MaterialTheme . Поскольку MaterialTheme по умолчанию устанавливает цвета, типографику и формы в соответствии с текущим значением темы, все остальные параметры сохраняют значения по умолчанию, даже если тема задаёт только один из этих параметров.
Кроме того, при переносе экранов View-based в Compose обратите внимание на использование атрибута android:theme . Вероятно, вам понадобится новая MaterialTheme в этой части дерева пользовательского интерфейса Compose.
В этом примере экран сведений использует тему PinkTheme для большей части экрана, а затем тему BlueTheme для соответствующего раздела. Следующий снимок экрана и код иллюстрируют эту концепцию:

@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
Состояния компонентов
Материальные компоненты, с которыми можно взаимодействовать (кликать, переключать и т. д.), могут находиться в различных визуальных состояниях. Состояния включают в себя «включено», «выключено», «нажато» и т. д.
У компонуемых компонентов часто есть параметр enabled . Установка его в false блокирует взаимодействие и изменяет такие свойства, как цвет и высота, визуально отражая состояние компонента.

enabled = true (слева) и enabled = false (справа).В большинстве случаев для таких значений, как цвет и высота, можно использовать значения по умолчанию. Если вам нужно настроить значения, используемые в разных состояниях, доступны классы и удобные функции. Рассмотрим следующий пример кнопки:
Button( onClick = { /* ... */ }, enabled = true, // Custom colors for different states colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary, disabledBackgroundColor = MaterialTheme.colors.onBackground .copy(alpha = 0.2f) .compositeOver(MaterialTheme.colors.background) // Also contentColor and disabledContentColor ), // Custom elevation for different states elevation = ButtonDefaults.elevation( defaultElevation = 8.dp, disabledElevation = 2.dp, // Also pressedElevation ) ) { /* ... */ }

enabled = true (слева) и enabled = false (справа) с настроенными значениями цвета и высоты.Рябь
Компоненты материалов используют рябь для обозначения взаимодействия с ними. Если в вашей иерархии используется MaterialTheme , Ripple используется в качестве Indication по умолчанию внутри модификаторов, таких как clickable и indication .
В большинстве случаев вы можете положиться на Ripple по умолчанию. Если вам нужно настроить внешний вид, используйте RippleTheme для изменения таких свойств, как цвет и альфа-канал.
Вы можете расширить RippleTheme и использовать служебные функции defaultRippleColor и defaultRippleAlpha . Затем вы можете добавить свою собственную тему Ripple в свою иерархию с помощью LocalRippleTheme :
@Composable fun MyApp() { MaterialTheme { CompositionLocalProvider( LocalRippleTheme provides SecondaryRippleTheme ) { // App content } } } @Immutable private object SecondaryRippleTheme : RippleTheme { @Composable override fun defaultColor() = RippleTheme.defaultRippleColor( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) @Composable override fun rippleAlpha() = RippleTheme.defaultRippleAlpha( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) }

RippleTheme .Узнать больше
Чтобы узнать больше о Material Theming в Compose, ознакомьтесь со следующими дополнительными ресурсами.
Codelabs
Видео
{% дословно %}Рекомендовано для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Системы индивидуального дизайна в Compose
- Переход из Material 2 в Material 3 в Compose
- Доступность в Compose