Jetpack Compose מציע הטמעה של Material Design, מערכת עיצוב מקיפה ליצירת ממשקים דיגיטליים. הרכיבים של Material Design (כפתורים, כרטיסים, מתגים וכו') מבוססים על התאמת העיצוב של Google Material Design, שהיא שיטה שיטתית להתאמה אישית של 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), // ... ) { /* ... */ }
כך אפשר לא רק להגדיר את הצבע של רכיב ה-composable, אלא גם לספק צבע ברירת מחדל לתוכן,כלומר לרכיבי ה-composable שכלולים בו. הרבה רכיבים קומפוזביליים משתמשים בצבע התוכן הזה כברירת מחדל. לדוגמה, הצבע של Text מבוסס על צבע התוכן של הרכיב הראשי שלו, והגוון של Icon מבוסס על הצבע הזה.
השיטה contentColorFor() מאחזרת את הצבע המתאים לכל צבעי העיצוב. לדוגמה, אם מגדירים צבע רקע primary ב-Surface, הפונקציה הזו מגדירה את onPrimary כצבע התוכן.
אם אתם מגדירים צבע רקע שלא שייך לעיצוב, אתם צריכים גם לציין צבע תוכן מתאים. משתמשים ב-LocalContentColor כדי לאחזר את צבע התוכן המועדף לרקע הנוכחי, במיקום נתון בהיררכיה.
תוכן בגרסת אלפא
לפעמים רוצים להדגיש את התוכן במידה שונה כדי להעביר את החשיבות שלו ולספק היררכיה חזותית. בהמלצות של Material Design בנושא קריאוּת טקסט מומלץ להשתמש ברמות שונות של אטימוּת כדי להעביר רמות חשיבות שונות.
ב-Jetpack Compose, זה מיושם באמצעות LocalContentAlpha. כדי לציין גרסת אלפא של תוכן להיררכיה, מזינים ערך בCompositionLocal הזה. רכיבי Composable בתצוגת עץ יכולים להשתמש בערך הזה כדי להחיל את הטיפול באלפא על התוכן שלהם. לדוגמה, ב-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 ל-composable של 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 ומחלקות שקשורות לגופנים. ה-constructor של 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 )
צורה
ב-Material מוגדרת מערכת צורות, שמאפשרת להגדיר צורות לרכיבים גדולים, בינוניים וקטנים.
ב-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. כדי לספק פונקציונליות דומה, אתם יכולים ליצור 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 ב-Compose, אפשר להוסיף רכיבי MaterialTheme composable בתצוגת עץ. מכיוון ש-MaterialTheme מגדיר את הצבעים, הטיפוגרפיה והצורות כברירת מחדל לערך העיצוב הנוכחי, כל שאר הפרמטרים שומרים על ערכי ברירת המחדל שלהם כשעיצוב מגדיר רק אחד מהפרמטרים האלה.
בנוסף, כשמעבירים מסכים מבוססי-View לפיתוח נייטיב, חשוב לשים לב לשימושים במאפיין android:theme. סביר להניח שצריך MaterialTheme חדש
בחלק הזה של עץ ממשק המשתמש של Compose.
בדוגמה הזו, מסך הפרטים משתמש ב-PinkTheme ברוב המסך, וב-BlueTheme בקטע הקשור. צילום המסך והקוד הבאים ממחישים את הרעיון הזה:
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
מצבי הרכיבים
רכיבי Material שאפשר לבצע איתם אינטראקציה (ללחוץ, להחליף מצב וכו') יכולים להיות במצבים חזותיים שונים. המצבים כוללים: מופעל, מושבת, לחוץ וכו'.
לרכיבים קומפוזביליים יש בדרך כלל פרמטר 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 (מימין), עם ערכים מותאמים של צבע וגובה.אדוות
רכיבי Material משתמשים באפקט של אדוות כדי לציין שמתבצעת איתם אינטראקציה. אם אתם משתמשים ב-MaterialTheme בהיררכיה, Ripple משמש כברירת המחדל של Indication בתוך מגבילי גישה כמו clickable ו-indication.
ברוב המקרים אפשר להסתמך על ברירת המחדל Ripple. כדי לשנות את המראה שלהם, אתם יכולים להשתמש ב-RippleTheme כדי לשנות מאפיינים כמו צבע ואלפא.
אפשר להרחיב את RippleTheme ולהשתמש בפונקציות הבסיסיות defaultRippleColor ו-defaultRippleAlpha. אחרי זה, אתם יכולים לספק את העיצוב המותאם אישית של האפקט בהיררכיה באמצעות 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 ) }
RippleConfiguration.מידע נוסף
כדי לקבל מידע נוסף על התאמת העיצוב של Google Material Design ב-Compose, אפשר לעיין במקורות המידע הנוספים הבאים.
Codelabs
סרטונים
מומלץ בשבילכם
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- מערכות עיצוב בהתאמה אישית ב-Compose
- מעבר מ-Material 2 ל-Material 3 ב-Compose
- נגישות ב-Compose