Während Material als Designsystem empfohlen wird, liefert Jetpack Compose eine von Material implementiert ist, sind Sie nicht gezwungen, es zu nutzen. Das Material wird entwickelt vollständig auf öffentlichen APIs basieren, sodass Sie Ihr eigenes Designsystem in auf die gleiche Weise.
Dafür gibt es mehrere Ansätze:
MaterialTheme
mit zusätzlichen Themen erweitern Werte- Ein oder mehrere Materialsysteme ersetzen:
Colors
,Typography
oderShapes
– mit benutzerdefinierten Implementierungen und die anderen - Ein vollständig angepasstes Designsystem implementieren,
MaterialTheme
ersetzen
Sie können auch weiterhin Material-Komponenten mit einem benutzerdefinierten Design verwenden. System. Das ist möglich, aber es gibt einige Dinge zu beachten, Ihren Ansatz.
Weitere Informationen zu den untergeordneten Konstrukten und APIs, die von MaterialTheme
verwendet werden
und benutzerdefinierte Designsysteme erhalten, finden Sie im Leitfaden Aufbau eines Designs im Editor.
Material-Design erweitern
Stark modelliertes Material zusammenstellen Material-Design damit es einfach und typsicher ist. Es ist jedoch Farben, Typografie und Form mit weiteren Werte.
Der einfachste Ansatz besteht darin, Erweiterungseigenschaften hinzuzufügen:
// Use with MaterialTheme.colors.snackbarAction val Colors.snackbarAction: Color get() = if (isLight) Red300 else Red700 // Use with MaterialTheme.typography.textFieldInput val Typography.textFieldInput: TextStyle get() = TextStyle(/* ... */) // Use with MaterialTheme.shapes.card val Shapes.card: Shape get() = RoundedCornerShape(size = 20.dp)
Dies sorgt für Konsistenz mit den MaterialTheme
-Nutzungs-APIs. Ein Beispiel:
Compose-Datei definiert,
primarySurface
,
der als Proxy zwischen primary
und surface
fungiert,
Colors.isLight
Ein anderer Ansatz besteht darin, ein erweitertes Thema zu definieren, das MaterialTheme
und
ihre Werte.
Angenommen, Sie möchten die beiden zusätzlichen Farben tertiary
und onTertiary
hinzufügen.
und die vorhandenen Material-Farben beibehalten:
@Immutable data class ExtendedColors( val tertiary: Color, val onTertiary: Color ) val LocalExtendedColors = staticCompositionLocalOf { ExtendedColors( tertiary = Color.Unspecified, onTertiary = Color.Unspecified ) } @Composable fun ExtendedTheme( /* ... */ content: @Composable () -> Unit ) { val extendedColors = ExtendedColors( tertiary = Color(0xFFA8EFF0), onTertiary = Color(0xFF002021) ) CompositionLocalProvider(LocalExtendedColors provides extendedColors) { MaterialTheme( /* colors = ..., typography = ..., shapes = ... */ content = content ) } } // Use with eg. ExtendedTheme.colors.tertiary object ExtendedTheme { val colors: ExtendedColors @Composable get() = LocalExtendedColors.current }
Dies ähnelt den Nutzungs-APIs für MaterialTheme
. Es werden auch mehrere Designs unterstützt.
da du ExtendedTheme
s auf dieselbe Weise verschachteln kannst wie MaterialTheme
.
Material-Komponenten verwenden
Beim Erweitern von Material Theming werden vorhandene MaterialTheme
-Werte beibehalten.
und Material-Komponenten haben
noch angemessene Standardeinstellungen.
Wenn Sie erweiterte Werte in Komponenten verwenden möchten, schließen Sie sie in Ihre eigenen ein. zusammensetzbare Funktionen verwenden, die zu ändernden Werte direkt festlegen und andere als Parameter an die enthaltene zusammensetzbare Funktion übergeben:
@Composable fun ExtendedButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( containerColor = ExtendedTheme.colors.tertiary, contentColor = ExtendedTheme.colors.onTertiary /* Other colors use values from MaterialTheme */ ), onClick = onClick, modifier = modifier, content = content ) }
Dann würden Sie die Verwendungen von Button
durch ExtendedButton
ersetzen, wobei
angemessen sein.
@Composable fun ExtendedApp() { ExtendedTheme { /*...*/ ExtendedButton(onClick = { /* ... */ }) { /* ... */ } } }
Materialsysteme ersetzen
Anstatt Material Theming zu erweitern, können Sie ein oder mehrere
Colors
, Typography
oder Shapes
mit einer benutzerdefinierten Implementierung,
und die anderen beibehalten.
Angenommen, Sie möchten das Schrift- und Formsystem ersetzen, die Farbe System:
@Immutable data class ReplacementTypography( val body: TextStyle, val title: TextStyle ) @Immutable data class ReplacementShapes( val component: Shape, val surface: Shape ) val LocalReplacementTypography = staticCompositionLocalOf { ReplacementTypography( body = TextStyle.Default, title = TextStyle.Default ) } val LocalReplacementShapes = staticCompositionLocalOf { ReplacementShapes( component = RoundedCornerShape(ZeroCornerSize), surface = RoundedCornerShape(ZeroCornerSize) ) } @Composable fun ReplacementTheme( /* ... */ content: @Composable () -> Unit ) { val replacementTypography = ReplacementTypography( body = TextStyle(fontSize = 16.sp), title = TextStyle(fontSize = 32.sp) ) val replacementShapes = ReplacementShapes( component = RoundedCornerShape(percent = 50), surface = RoundedCornerShape(size = 40.dp) ) CompositionLocalProvider( LocalReplacementTypography provides replacementTypography, LocalReplacementShapes provides replacementShapes ) { MaterialTheme( /* colors = ... */ content = content ) } } // Use with eg. ReplacementTheme.typography.body object ReplacementTheme { val typography: ReplacementTypography @Composable get() = LocalReplacementTypography.current val shapes: ReplacementShapes @Composable get() = LocalReplacementShapes.current }
Material-Komponenten verwenden
Wenn eines oder mehrere Systeme von MaterialTheme
mit Material ersetzt wurden
Komponenten in unveränderter Form zu unerwünschten Farb-, Typ- oder Formwerten für Material führen.
Wenn Sie Ersatzwerte in Komponenten verwenden möchten, schließen Sie sie in Ihre eigenen ein. zusammensetzbaren Funktionen verwenden, die Werte direkt für das jeweilige System festlegen und andere als Parameter an die enthaltene zusammensetzbare Funktion übergeben.
@Composable fun ReplacementButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( shape = ReplacementTheme.shapes.component, onClick = onClick, modifier = modifier, content = { ProvideTextStyle( value = ReplacementTheme.typography.body ) { content() } } ) }
Dann würden Sie die Verwendungen von Button
durch ReplacementButton
ersetzen, wobei
angemessen sein.
@Composable fun ReplacementApp() { ReplacementTheme { /*...*/ ReplacementButton(onClick = { /* ... */ }) { /* ... */ } } }
Vollständig kundenspezifisches Designsystem implementieren
Sie können Material Theming durch ein vollständig benutzerdefiniertes Designsystem ersetzen.
MaterialTheme
bietet die folgenden Systeme:
Colors
,Typography
undShapes
: Material Theming-SystemeContentAlpha
: Deckkraft zur Hervorhebung inText
undIcon
TextSelectionColors
: Farben für die Textauswahl vonText
undTextField
Ripple
undRippleTheme
: Materialisierte Implementierung vonIndication
Wenn Sie weiterhin Material-Komponenten verwenden möchten, benutzerdefinierten Designs erstellen oder die Systeme in Ihrem um unerwünschtes Verhalten zu vermeiden.
Designsysteme sind jedoch nicht auf die Konzepte beschränkt, auf denen das Material basiert. Ich bestehende Systeme modifizieren und ganz neue einführen – mit neuen Klassen und Typen hinzufügen, um andere Konzepte mit Themen kompatibel zu machen.
Im folgenden Code wird ein benutzerdefiniertes Farbsystem mit Farbverläufen modelliert
(List<Color>
), enthalten ein Schriftsystem, führen ein neues Höhensystem ein,
und andere von MaterialTheme
bereitgestellte Systeme ausschließen:
@Immutable data class CustomColors( val content: Color, val component: Color, val background: List<Color> ) @Immutable data class CustomTypography( val body: TextStyle, val title: TextStyle ) @Immutable data class CustomElevation( val default: Dp, val pressed: Dp ) val LocalCustomColors = staticCompositionLocalOf { CustomColors( content = Color.Unspecified, component = Color.Unspecified, background = emptyList() ) } val LocalCustomTypography = staticCompositionLocalOf { CustomTypography( body = TextStyle.Default, title = TextStyle.Default ) } val LocalCustomElevation = staticCompositionLocalOf { CustomElevation( default = Dp.Unspecified, pressed = Dp.Unspecified ) } @Composable fun CustomTheme( /* ... */ content: @Composable () -> Unit ) { val customColors = CustomColors( content = Color(0xFFDD0D3C), component = Color(0xFFC20029), background = listOf(Color.White, Color(0xFFF8BBD0)) ) val customTypography = CustomTypography( body = TextStyle(fontSize = 16.sp), title = TextStyle(fontSize = 32.sp) ) val customElevation = CustomElevation( default = 4.dp, pressed = 8.dp ) CompositionLocalProvider( LocalCustomColors provides customColors, LocalCustomTypography provides customTypography, LocalCustomElevation provides customElevation, content = content ) } // Use with eg. CustomTheme.elevation.small object CustomTheme { val colors: CustomColors @Composable get() = LocalCustomColors.current val typography: CustomTypography @Composable get() = LocalCustomTypography.current val elevation: CustomElevation @Composable get() = LocalCustomElevation.current }
Material-Komponenten verwenden
Wenn kein MaterialTheme
vorhanden ist, führt die Verwendung der unveränderten Material-Komponenten zur Folge.
in unerwünschtem Material-Farb-, Schrift- und Formwerte sowie in Anzeigeverhalten angezeigt.
Wenn Sie benutzerdefinierte Werte in Komponenten verwenden möchten, schließen Sie diese in Ihre eigene zusammensetzbare Funktion ein. die Werte für das relevante System direkt festlegen und andere Parameter als Parameter für die zusammensetzbare Funktion verwenden, in der sie enthalten ist.
Wir empfehlen, auf Werte zuzugreifen, die Sie in Ihrem benutzerdefinierten Design festgelegt haben. Wenn Sie alternativ
Ihr Design unterstützt Color
, TextStyle
, Shape
oder andere Systeme nicht. Sie
hartcodieren können.
@Composable fun CustomButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( containerColor = CustomTheme.colors.component, contentColor = CustomTheme.colors.content, disabledContainerColor = CustomTheme.colors.content .copy(alpha = 0.12f) .compositeOver(CustomTheme.colors.component), disabledContentColor = CustomTheme.colors.content .copy(alpha = ContentAlpha.disabled) ), shape = ButtonShape, elevation = ButtonDefaults.elevatedButtonElevation( defaultElevation = CustomTheme.elevation.default, pressedElevation = CustomTheme.elevation.pressed /* disabledElevation = 0.dp */ ), onClick = onClick, modifier = modifier, content = { ProvideTextStyle( value = CustomTheme.typography.body ) { content() } } ) } val ButtonShape = RoundedCornerShape(percent = 50)
Wenn Sie neue Klassentypen eingeführt haben, z. B. List<Color>
zur Darstellung von Farbverläufen, ist es möglicherweise besser, die Komponenten von Grund auf neu zu implementieren, anstatt sie zu umschließen. Sehen Sie sich zum Beispiel
JetsnackButton
aus dem Jetsnack-Sample.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Material Design 2 in Compose
- In Compose von Material 2 zu Material 3 migrieren
- Aufbau eines Designs in „Schreiben“