Material היא מערכת העיצוב המומלצת שלנו, ו-Jetpack פיתוח נייטיב כוללת הטמעה של Material, אבל אתם לא חייבים להשתמש בה. Material מבוסס כולו על ממשקי API ציבוריים, כך שאפשר ליצור מערכת עיצוב משלכם באותו אופן.
יש כמה גישות אפשריות:
- הרחבה של
MaterialThemeעם ערכים נוספים של עיצובים. - להחליף מערכת Material אחת או יותר –
Colors,TypographyאוShapes– בהטמעות מותאמות אישית, תוך שמירה על השאר. - הטמעה של מערכת עיצוב בהתאמה אישית מלאה כדי להחליף את
MaterialTheme.
אפשר גם להמשיך להשתמש ברכיבי Material עם מערכת עיצוב מותאמת אישית. אפשר לעשות את זה, אבל יש כמה דברים שכדאי לזכור כדי להתאים את הגישה שבחרתם.
מידע נוסף על מבנים ועל ממשקי API ברמה נמוכה יותר שמשמשים את MaterialTheme ומערכות עיצוב בהתאמה אישית זמין במדריך ממה מורכב עיצוב ב-Compose.
הרחבת התאמת העיצוב של Google Material Design
הספרייה Compose Material מבוססת על התאמת העיצוב של Google Material Design, ולכן קל ופשוט לפעול לפי ההנחיות של Material. עם זאת, אפשר להוסיף ערכים נוספים לערכות הצבעים, הטיפוגרפיה והצורות. הגישה הפשוטה ביותר היא להוסיף מאפיינים של תוסף:
// Use with MaterialTheme.colorScheme.snackbarAction val ColorScheme.snackbarAction: Color @Composable get() = if (isSystemInDarkTheme()) 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)
כך מתקבלת עקביות עם ממשקי API לשימוש ב-MaterialTheme. דוגמה לכך שמוגדרת על ידי Compose עצמה היא surfaceColorAtElevation, שקובעת את צבע הרקע שבו צריך להשתמש בהתאם לגובה.
גישה נוספת היא להגדיר עיצוב מורחב שכולל את MaterialTheme ואת הערכים שלו.
נניח שרוצים להוסיף עוד שני צבעים – caution ו-onCaution, צבע צהוב שמשמש לפעולות שהן מסוכנות למחצה – וגם לשמור על הצבעים הקיימים של Material:
@Immutable data class ExtendedColors( val caution: Color, val onCaution: Color ) val LocalExtendedColors = staticCompositionLocalOf { ExtendedColors( caution = Color.Unspecified, onCaution = Color.Unspecified ) } @Composable fun ExtendedTheme( /* ... */ content: @Composable () -> Unit ) { val extendedColors = ExtendedColors( caution = Color(0xFFFFCC02), onCaution = Color(0xFF2C2D30) ) CompositionLocalProvider(LocalExtendedColors provides extendedColors) { MaterialTheme( /* colors = ..., typography = ..., shapes = ... */ content = content ) } } // Use with eg. ExtendedTheme.colors.caution object ExtendedTheme { val colors: ExtendedColors @Composable get() = LocalExtendedColors.current }
הוא דומה לממשקי API לשימוש ב-MaterialTheme. הוא גם תומך בכמה ערכות נושא, כי אפשר להטמיע תגי ExtendedTheme באותו אופן כמו תגי MaterialTheme.
שימוש ברכיבי Material
כשמרחיבים את התאמת העיצוב של Google Material Design, הערכים הקיימים של MaterialTheme נשמרים, ורכיבי Material עדיין כוללים ערכי ברירת מחדל סבירים.
אם רוצים להשתמש בערכים מורחבים ברכיבים, צריך להוסיף אותם לפונקציות הניתנות להרכבה משלכם, להגדיר ישירות את הערכים שרוצים לשנות ולחשוף אחרים כפרמטרים לפונקציה הניתנת להרכבה שמכילה אותם:
@Composable fun ExtendedButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( containerColor = ExtendedTheme.colors.caution, contentColor = ExtendedTheme.colors.onCaution /* Other colors use values from MaterialTheme */ ), onClick = onClick, modifier = modifier, content = content ) }
לאחר מכן, מחליפים את השימוש ב-Button ב-ExtendedButton במקומות המתאימים.
@Composable fun ExtendedApp() { ExtendedTheme { /*...*/ ExtendedButton(onClick = { /* ... */ }) { /* ... */ } } }
החלפת מערכות משנה של חומרים
במקום להרחיב את התאמת העיצוב של Google Material Design, יכול להיות שתרצו להחליף מערכת אחת או יותר – Colors, Typography או Shapes – בהטמעה בהתאמה אישית, תוך שמירה על שאר המערכות.
נניח שרוצים להחליף את סוג המידה ואת שיטת הצורה, אבל להשאיר את שיטת הצבע:
@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
אם החלפתם מערכת אחת או יותר של MaterialTheme, יכול להיות ששימוש ברכיבי Material כמו שהם יניב ערכים לא רצויים של צבע, סוג או צורה של Material.
אם רוצים להשתמש בערכי החלפה ברכיבים, צריך להוסיף אותם לפונקציות הניתנות להרכבה, להגדיר ישירות את הערכים למערכת הרלוונטית ולחשוף אחרים כפרמטרים לרכיב הניתן להרכבה שמכיל אותם.
@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() } } ) }
לאחר מכן, מחליפים את השימוש ב-Button ב-ReplacementButton במקומות המתאימים.
@Composable fun ReplacementApp() { ReplacementTheme { /*...*/ ReplacementButton(onClick = { /* ... */ }) { /* ... */ } } }
הטמעה של מערכת עיצוב בהתאמה אישית מלאה
יכול להיות שתרצו להחליף את התאמת העיצוב של Google Material Design במערכת עיצוב מותאמת אישית לחלוטין.
נניח ש-MaterialTheme מספק את המערכות הבאות:
-
Colors,Typographyו-Shapes: מערכות של התאמת העיצוב של Google Material Design -
TextSelectionColors: הצבעים שמשמשים לבחירת טקסט על ידיTextו-TextField -
Rippleו-RippleTheme: הטמעת חומרים שלIndication
אם אתם רוצים להמשיך להשתמש ברכיבי Material, אתם צריכים להחליף חלק מהמערכות האלה בערכות הנושא המותאמות אישית שלכם או לטפל במערכות ברכיבים שלכם כדי למנוע התנהגות לא רצויה.
עם זאת, מערכות עיצוב לא מוגבלות למושגים ש-Material מסתמכת עליהם. אתם יכולים לשנות מערכות קיימות ולהציג מערכות חדשות לגמרי – עם מחלקות וסוגים חדשים – כדי להתאים מושגים אחרים לערכות נושא.
בדוגמת הקוד הבאה, אנחנו יוצרים מודל של מערכת צבעים בהתאמה אישית שכוללת מעברי צבע (List<Color>), כוללים מערכת סוגים, מציגים מערכת חדשה של גובה ומסננים מערכות אחרות שסופקו על ידי MaterialTheme:
@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
אם לא מציינים MaterialTheme, שימוש ברכיבי Material כמו שהם יגרום להצגת ערכים לא רצויים של צבע, סוג וצורה של Material, וגם להתנהגות לא רצויה של אינדיקטורים.
אם רוצים להשתמש בערכים מותאמים אישית ברכיבים, צריך לעטוף אותם בפונקציות שאפשר להוסיף להן קומפוזיציה, להגדיר ישירות את הערכים למערכת הרלוונטית ולחשוף אחרים כפרמטרים לפונקציה שאפשר להוסיף לה קומפוזיציה.
מומלץ לגשת לערכים שהגדרתם מהעיצוב המותאם אישית.
לחלופין, אם התבנית לא מספקת Color, TextStyle, Shape או מערכות אחרות, אפשר להגדיר אותן בהארדקוד.
@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 = 0.38f) ), 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)
אם הוספתם סוגים חדשים של מחלקות – כמו List<Color> כדי לייצג מעברי צבע – יכול להיות שעדיף להטמיע רכיבים מאפס במקום לעטוף אותם. לדוגמה, אפשר לעיין ב-JetsnackButton מהדוגמה של Jetsnack.
מומלץ בשבילך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- Material Design 3 ב-Compose
- העברה מ-Material 2 ל-Material 3 ב-Compose
- ממה מורכב עיצוב ב-Compose