Jetpack Compose מציע הטמעה של Material Design, מערכת עיצוב מקיפה ליצירת ממשקים דיגיטליים. רכיבי Material Design (כפתורים, כרטיסים, מתגים וכו') מבוססים על התאמת העיצוב של Google Material Design, שהיא שיטה שיטתית להתאמה אישית של Material Design כדי לשקף טוב יותר את המותג של המוצר. ערכת נושא של Material כוללת מאפיינים של צבע, טיפוגרפיה וצורה. כשאתם משנים את המאפיינים האלה, השינויים מתעדכנים אוטומטית ברכיבים שבהם אתם משתמשים כדי לבנות את האפליקציה.
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)
אפשר לארגן את הצבעים איך שרוצים (כקבועים ברמה העליונה, בתוך singleton או בהגדרה מוטבעת), אבל מומלץ מאוד לציין את הצבעים בערכת הנושא ולאחזר אותם משם. הגישה הזו מאפשרת תמיכה בעיצוב כהה ובעיצובים מוטמעים.
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 משתמש בצבע הזה כדי להגדיר את הגוון שלו.
ה-method 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 זמין במאמר Locally scoped data with
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 וfont-related. ה-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 Views. אתם יכולים ליצור פונקציות מורכבות משלכם שמכילות רכיבי Material כדי לספק פונקציונליות דומה.overload לדוגמה, כדי ליצור סגנון של לחצן, עוטפים לחצן בפונקציה קומפוזבילית משלכם, מגדירים ישירות את הפרמטרים שרוצים או צריכים לשנות, וחושפים אחרים כפרמטרים לפונקציה קומפוזבילית שמכילה אותו.
@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, אפשר להשתמש ב-composables של MaterialTheme. מכיוון ש-MaterialTheme מגדיר את ברירת המחדל של הצבעים, הטיפוגרפיה והצורות לערך הנושא הנוכחי, כל שאר הפרמטרים שומרים על ערכי ברירת המחדל שלהם כשנושא מגדיר רק אחד מהפרמטרים האלה.
בנוסף, כשמעבירים מסכים מבוססי-View לפיתוח נייטיב, צריך לשים לב לשימושים במאפיין android:theme. סביר להניח שצריך ליצור MaterialThemeחדש בחלק הזה של עץ ממשק המשתמש של הכתיבה.
בדוגמה הזו, במסך הפרטים נעשה שימוש ב-PinkTheme ברוב המסך, ואז ב-BlueTheme בקטע שקשור לנושא. בצילום המסך ובקוד הבאים מוצגת דוגמה למושג הזה:
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
מצבי הרכיבים
רכיבי Material שאפשר לקיים איתם אינטראקציה (ללחוץ עליהם, להפעיל או להשבית אותם וכו') יכולים להיות במצבים חזותיים שונים. הסטטוסים כוללים 'מופעל', 'מושבת', 'נלחץ' וכו'.
לרוב, לרכיבי Composables יש פרמטר 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