שינוי עיצוב ב'כתיבה' בעזרת Material 3

1. מבוא

ב-Codelab הזה נלמד איך להחיל ערכות עיצוב על האפליקציות שלכם ב-Jetpack פיתוח נייטיב באמצעות Material Design 3. תלמדו גם על אבני הבניין העיקריות של ערכות הצבעים, הטיפוגרפיה והצורות ב-Material Design 3, שיעזרו לכם להחיל עיצוב על האפליקציה בדרכים מותאמות אישית ונגישות.

בנוסף, תלמדו על תמיכה בשינוי דינמי של ערכות נושא ועל רמות שונות של הדגשה.

מה תלמדו

ב-codelab הזה תלמדו:

  • היבטים מרכזיים של התאמת עיצוב באמצעות Material 3
  • ערכות צבעים של Material 3 ואיך ליצור עיצובים לאפליקציה
  • איך תומכים בעיצוב דינמי ובעיצוב בהיר או כהה באפליקציה
  • טיפוגרפיה וצורות להתאמה אישית של האפליקציה
  • רכיבי Material 3 והתאמה אישית לעיצוב האפליקציה

מה תפַתחו

ב-Codelab הזה, תגדירו ערכת נושא לאפליקציית תוכנת אימייל בשם Reply. מתחילים עם אפליקציה ללא סגנון, באמצעות עיצוב בסיסי, ומיישמים את מה שלומדים כדי להגדיר עיצוב לאפליקציה ולתמוך בעיצובים כהים.

d15db3dc75a9d00f.png

נקודת ההתחלה שמוגדרת כברירת מחדל באפליקציה שלנו עם העיצוב הבסיסי.

תצרו את העיצוב עם ערכת צבעים, טיפוגרפיה וצורות, ואז תחיל אותו על רשימת כתובות האימייל ועל דף הפרטים של האפליקציה. בנוסף, תוסיפו לאפליקציה תמיכה בערכות נושא דינמיות. בסיום ה-codelab, האפליקציה שלכם תתמוך גם בצבעים וגם בערכות נושא דינמיות.

1357cdbfaaa67721.png

נקודת הסיום של ה-Codelab בנושא עיצוב ערכות נושא עם עיצוב ערכות נושא בצבע בהיר ועיצוב ערכות נושא דינמיות בהירות.

1357cdbfaaa67721.png

נקודת הסיום של ה-Codelab בנושא עיצוב עם ערכת נושא כהה ועיצוב דינמי כהה.

מה צריך

2. תהליך ההגדרה

בשלב הזה מורידים את הקוד המלא של אפליקציית Reply, שבה תעצבו את המראה של האפליקציה ב-codelab הזה.

קבל את הקוד

הקוד של ה-Codelab הזה נמצא במאגר GitHub‏ android-compose-codelabs. כדי לשכפל אותו, מריצים את הפקודה:

$ git clone https://github.com/googlecodelabs/android-compose-codelabs

לחלופין, אפשר להוריד שני קובצי ZIP:

בדיקת האפליקציה לדוגמה

הקוד שהורדתם עכשיו מכיל קוד לכל מעבדות ה-codelab הזמינות של Compose. כדי להשלים את ה-codelab הזה, פותחים את הפרויקט ThemingCodelab ב-Android Studio.

מומלץ להתחיל עם הקוד בענף הראשי ולעבור על השלבים ב-Codelab בקצב שלכם. בכל שלב, אפשר להריץ כל אחת מהגרסאות ב-Android Studio על ידי שינוי הענף של git בפרויקט.

הסבר על קוד ההתחלה

הקוד הראשי מכיל חבילת UI, שכוללת את החבילות והקבצים העיקריים הבאים שבהם תשתמשו:

  • MainActivity.kt – פעילות נקודת הכניסה שבה מתחילים את אפליקציית Reply.
  • com.example.reply.ui.theme – החבילה הזו מכילה עיצובים, טיפוגרפיה וערכות צבעים. תתווסף לחבילה הזו ערכת נושא של Material.
  • com.example.reply.ui.components – מכיל את הרכיבים המותאמים אישית של האפליקציה, כמו פריטים ברשימה, סרגלי אפליקציה וכו'. תחילת העיצוב של הרכיבים האלה.
  • ReplyApp.kt – זו הפונקציה הניתנת להגדרה הראשית שבה יתחיל עץ ממשק המשתמש. תחילת העיצוב ברמה העליונה בקובץ הזה.

ב-Codelab הזה נתמקד בקובצי חבילות ui.

3. התאמת עיצוב של Material 3

‫Jetpack פיתוח נייטיב מציע הטמעה של Material Design – מערכת עיצוב מקיפה ליצירת ממשקים דיגיטליים. רכיבי Material Design (לחצנים, כרטיסים, מתגים וכו') מבוססים על התאמת העיצוב של Google Material Design, שהיא שיטה שיטתית להתאמה אישית של Material Design כדי לשקף טוב יותר את המותג של המוצר.

העיצוב של Material 3 כולל את מערכות המשנה הבאות, שמאפשרות להוסיף עיצוב לאפליקציה: סכמת צבעים, טיפוגרפיה וצורות. כשמתאימים אישית את הערכים האלה, השינויים משתקפים באופן אוטומטי ברכיבי M3 שבהם משתמשים כדי ליצור את האפליקציה. נצלול לכל אחת ממערכות המשנה ונראה איך מטמיעים אותה באפליקציה לדוגמה.

מערכות משנה של עיצוב Material: צבע, טיפוגרפיה וצורות.

מערכת משנה של צבעים, טיפוגרפיה וצורות של Material 3.

4. ערכות של צבעים

הבסיס של ערכת צבעים הוא קבוצה של חמישה צבעים ראשיים, שכל אחד מהם קשור לפלטת גוונים של 13 גוונים שמשמשים את רכיבי Material 3.

חמישה צבעי בסיס ליצירת ערכת נושא M3.

חמישה צבעי בסיס ליצירת ערכת נושא M3.

כל צבע הדגשה (ראשי, משני ושלישוני) מוצג בארבעה צבעים תואמים בגוונים שונים, כדי ליצור שילובים, להדגיש אלמנטים ולבטא את המותג באופן ויזואלי.

ארבעה צבעים טונאליים של צבעי הדגשה ראשיים, משניים ושלישוניים.

ארבעה צבעים טונאליים של צבעי הדגשה ראשיים, משניים ושלישוניים.

באופן דומה, גם הצבעים הניטרליים מחולקים לארבעה גוונים תואמים שמשמשים לרקע ולמשטחים. הם חשובים גם להדגשת סמלי טקסט כשמציבים אותם בכל פלטפורמה.

ארבעה צבעים מונוכרומטיים של צבעים ניטרליים בסיסיים.

ארבעה צבעים טונאליים של צבעים ניטרליים בסיסיים.

מידע נוסף על סכמת צבעים ותפקידי צבעים

יצירת ערכות צבעים

אפשר ליצור ColorScheme מותאם אישית באופן ידני, אבל לרוב קל יותר ליצור אותו באמצעות צבעי מקור מהמותג. אפשר לעשות את זה באמצעות הכלי Material Theme Builder, ואפשר גם לייצא קוד של ערכות נושא של Compose.

אתם יכולים לבחור כל צבע שתרצו, אבל בתרחיש השימוש שלנו תשתמשו בצבע הראשי של התשובה שמוגדר כברירת מחדל #825500. בקטע Core colors (צבעים מרכזיים) שבצד ימין, לוחצים על Primary (ראשי) ומוסיפים את הקוד בכלי לבחירת צבעים.

294f73fc9d2a570e.png

הוספת קוד הצבע הראשי בכלי Material Theme Builder.

אחרי שמוסיפים את הצבע הראשי בכלי ליצירת עיצוב Material, העיצוב הבא אמור להופיע בפינה השמאלית העליונה, עם האפשרות לייצא אותו. ב-Codelab הזה מייצאים את העיצוב ב-Jetpack פיתוח נייטיב.

כלי ליצירת ערכות עיצוב של Material עם אפשרות לייצא בפינה השמאלית העליונה.

כלי ליצירת ערכות עיצוב של Material עם אפשרות לייצא בפינה השמאלית העליונה.

הצבע הראשי #825500 יוצר את העיצוב הבא שתוסיפו לאפליקציה. בספריית Material 3 יש מגוון רחב של תפקידי צבעים שמאפשרים להביע באופן גמיש את המצב, הבולטות וההדגשה של רכיב.

ייצאנו ערכת צבעים בהירה וכהה מהצבע הראשי.

ערכת צבעים בהירה וכהה שיוצאה מהצבע הראשי.

The Color.kt הקובץ שנוצר מכיל את הצבעים של העיצוב עם כל התפקידים שמוגדרים לצבעי העיצוב במצב בהיר ובמצב כהה.

Color.kt

package com.example.reply.ui.theme
import androidx.compose.ui.graphics.Color

val md_theme_light_primary = Color(0xFF825500)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFFFFDDB3)
val md_theme_light_onPrimaryContainer = Color(0xFF291800)
val md_theme_light_secondary = Color(0xFF6F5B40)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFFBDEBC)
val md_theme_light_onSecondaryContainer = Color(0xFF271904)
val md_theme_light_tertiary = Color(0xFF51643F)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFD4EABB)
val md_theme_light_onTertiaryContainer = Color(0xFF102004)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFFFBFF)
val md_theme_light_onBackground = Color(0xFF1F1B16)
val md_theme_light_surface = Color(0xFFFFFBFF)
val md_theme_light_onSurface = Color(0xFF1F1B16)
val md_theme_light_surfaceVariant = Color(0xFFF0E0CF)
val md_theme_light_onSurfaceVariant = Color(0xFF4F4539)
val md_theme_light_outline = Color(0xFF817567)
val md_theme_light_inverseOnSurface = Color(0xFFF9EFE7)
val md_theme_light_inverseSurface = Color(0xFF34302A)
val md_theme_light_inversePrimary = Color(0xFFFFB951)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_light_surfaceTint = Color(0xFF825500)
val md_theme_light_outlineVariant = Color(0xFFD3C4B4)
val md_theme_light_scrim = Color(0xFF000000)

val md_theme_dark_primary = Color(0xFFFFB951)
val md_theme_dark_onPrimary = Color(0xFF452B00)
val md_theme_dark_primaryContainer = Color(0xFF633F00)
val md_theme_dark_onPrimaryContainer = Color(0xFFFFDDB3)
val md_theme_dark_secondary = Color(0xFFDDC2A1)
val md_theme_dark_onSecondary = Color(0xFF3E2D16)
val md_theme_dark_secondaryContainer = Color(0xFF56442A)
val md_theme_dark_onSecondaryContainer = Color(0xFFFBDEBC)
val md_theme_dark_tertiary = Color(0xFFB8CEA1)
val md_theme_dark_onTertiary = Color(0xFF243515)
val md_theme_dark_tertiaryContainer = Color(0xFF3A4C2A)
val md_theme_dark_onTertiaryContainer = Color(0xFFD4EABB)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF1F1B16)
val md_theme_dark_onBackground = Color(0xFFEAE1D9)
val md_theme_dark_surface = Color(0xFF1F1B16)
val md_theme_dark_onSurface = Color(0xFFEAE1D9)
val md_theme_dark_surfaceVariant = Color(0xFF4F4539)
val md_theme_dark_onSurfaceVariant = Color(0xFFD3C4B4)
val md_theme_dark_outline = Color(0xFF9C8F80)
val md_theme_dark_inverseOnSurface = Color(0xFF1F1B16)
val md_theme_dark_inverseSurface = Color(0xFFEAE1D9)
val md_theme_dark_inversePrimary = Color(0xFF825500)
val md_theme_dark_shadow = Color(0xFF000000)
val md_theme_dark_surfaceTint = Color(0xFFFFB951)
val md_theme_dark_outlineVariant = Color(0xFF4F4539)
val md_theme_dark_scrim = Color(0xFF000000)


val seed = Color(0xFF825500)

The Theme.kt הקובץ שנוצר מכיל הגדרה של ערכות צבעים בהירות וכהות ושל העיצוב של האפליקציה. הוא מכיל גם את פונקציית העיצוב הראשית הניתנת להגדרה, AppTheme().

Theme.kt

package com.example.reply.ui.theme

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable


private val LightColors = lightColorScheme(
   primary = md_theme_light_primary,
   onPrimary = md_theme_light_onPrimary,
   primaryContainer = md_theme_light_primaryContainer,
   onPrimaryContainer = md_theme_light_onPrimaryContainer,
   secondary = md_theme_light_secondary,
   onSecondary = md_theme_light_onSecondary,
   secondaryContainer = md_theme_light_secondaryContainer,
   onSecondaryContainer = md_theme_light_onSecondaryContainer,
   tertiary = md_theme_light_tertiary,
   onTertiary = md_theme_light_onTertiary,
   tertiaryContainer = md_theme_light_tertiaryContainer,
   onTertiaryContainer = md_theme_light_onTertiaryContainer,
   error = md_theme_light_error,
   errorContainer = md_theme_light_errorContainer,
   onError = md_theme_light_onError,
   onErrorContainer = md_theme_light_onErrorContainer,
   background = md_theme_light_background,
   onBackground = md_theme_light_onBackground,
   surface = md_theme_light_surface,
   onSurface = md_theme_light_onSurface,
   surfaceVariant = md_theme_light_surfaceVariant,
   onSurfaceVariant = md_theme_light_onSurfaceVariant,
   outline = md_theme_light_outline,
   inverseOnSurface = md_theme_light_inverseOnSurface,
   inverseSurface = md_theme_light_inverseSurface,
   inversePrimary = md_theme_light_inversePrimary,
   surfaceTint = md_theme_light_surfaceTint,
   outlineVariant = md_theme_light_outlineVariant,
   scrim = md_theme_light_scrim,
)


private val DarkColors = darkColorScheme(
   primary = md_theme_dark_primary,
   onPrimary = md_theme_dark_onPrimary,
   primaryContainer = md_theme_dark_primaryContainer,
   onPrimaryContainer = md_theme_dark_onPrimaryContainer,
   secondary = md_theme_dark_secondary,
   onSecondary = md_theme_dark_onSecondary,
   secondaryContainer = md_theme_dark_secondaryContainer,
   onSecondaryContainer = md_theme_dark_onSecondaryContainer,
   tertiary = md_theme_dark_tertiary,
   onTertiary = md_theme_dark_onTertiary,
   tertiaryContainer = md_theme_dark_tertiaryContainer,
   onTertiaryContainer = md_theme_dark_onTertiaryContainer,
   error = md_theme_dark_error,
   errorContainer = md_theme_dark_errorContainer,
   onError = md_theme_dark_onError,
   onErrorContainer = md_theme_dark_onErrorContainer,
   background = md_theme_dark_background,
   onBackground = md_theme_dark_onBackground,
   surface = md_theme_dark_surface,
   onSurface = md_theme_dark_onSurface,
   surfaceVariant = md_theme_dark_surfaceVariant,
   onSurfaceVariant = md_theme_dark_onSurfaceVariant,
   outline = md_theme_dark_outline,
   inverseOnSurface = md_theme_dark_inverseOnSurface,
   inverseSurface = md_theme_dark_inverseSurface,
   inversePrimary = md_theme_dark_inversePrimary,
   surfaceTint = md_theme_dark_surfaceTint,
   outlineVariant = md_theme_dark_outlineVariant,
   scrim = md_theme_dark_scrim,
)

@Composable
fun AppTheme(
   useDarkTheme: Boolean = isSystemInDarkTheme(),
   content: @Composable() () -> Unit
) {
   val colors = if (!useDarkTheme) {
       LightColors
   } else {
       DarkColors
   }

   MaterialTheme(
       colorScheme = colors,
       content = content
   )
}

הרכיב המרכזי להטמעת ערכות נושא ב-Jetpack פיתוח נייטיב הוא הקוד הקומפוזבילי MaterialTheme.

עוטפים את ה-composable MaterialTheme() בפונקציה AppTheme(), שמקבלת שני פרמטרים:

  • useDarkTheme – הפרמטר הזה קשור לפונקציה isSystemInDarkTheme() שמאפשרת להתאים את העיצוב להגדרות העיצוב של המערכת ולהחיל את העיצוב הבהיר או הכהה. אם רוצים להגדיר ידנית את העיצוב של האפליקציה כבהיר או כהה, אפשר להעביר ערך בוליאני אל useDarkTheme.
  • content – התוכן שיוחל עליו העיצוב.

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean = isSystemInDarkTheme(),
   content: @Composable() () -> Unit
) {
   val colors = if (!useDarkTheme) {
       LightColors
   } else {
       DarkColors
   }

   MaterialTheme(
       colorScheme = colors,
       content = content
   )
}

אם תנסו להריץ את האפליקציה עכשיו, תראו שהיא נראית אותו דבר. למרות שייבאתם את ערכת הצבעים החדשה שלנו עם צבעי עיצוב חדשים, אתם עדיין רואים את עיצוב הבסיס כי לא החלתם את העיצוב על אפליקציית Compose.

אפליקציה עם עיצוב בסיסי כשלא מוחל עיצוב.

אפליקציה עם עיצוב בסיסי כשלא מוחל עיצוב.

כדי להחיל את העיצוב החדש, ב-MainActivity.kt, עוטפים את הפונקציה העיקרית הניתנת להגדרה ReplyApp בפונקציית העיצוב הראשית, AppTheme().

MainActivity.kt

setContent {
   val uiState by viewModel.uiState.collectAsStateWithLifecycle()

   AppTheme {
       ReplyApp(/*..*/)
   }
}

תצטרכו גם לעדכן את פונקציות התצוגה המקדימה כדי לראות את העיצוב שמוחל על התצוגות המקדימות של האפליקציה. כדי להחיל את ערכת העיצוב על התצוגות המקדימות, עוטפים את הקומפוזיציה ReplyApp ב-ReplyAppPreview() עם AppTheme.

הגדרתם את העיצוב הבהיר והכהה של המערכת בפרמטרים של התצוגה המקדימה, ולכן תראו את שתי התצוגות המקדימות.

MainActivity.kt

@Preview(
   uiMode = Configuration.UI_MODE_NIGHT_YES,
   name = "DefaultPreviewDark"
)
@Preview(
   uiMode = Configuration.UI_MODE_NIGHT_NO,
   name = "DefaultPreviewLight"
)
@Composable
fun ReplyAppPreview() {
   AppTheme {
       ReplyApp(
           replyHomeUIState = ReplyHomeUIState(
               emails = LocalEmailsDataProvider.allEmails
           )
       )
   }
}

אם מריצים את האפליקציה עכשיו, אמורים לראות תצוגות מקדימות של האפליקציה עם צבעי העיצוב המיובאים במקום העיצוב הבסיסי.

fddf7b9cc99b1fe3.png be7a661b4553167b.png

אפליקציה עם עיצוב בסיסי (משמאל).

אפליקציה עם ערכת צבעים מיובאת (מימין).

674cec6cc12db6a0.png

תצוגות מקדימות של אפליקציות בעיצוב בהיר ובעיצוב כהה עם ערכות נושא של צבעים שיובאו.

‫Material 3 תומך גם בסכמות צבעים בהירות וגם בסכמות צבעים כהות. השתמשתם רק בערכת הנושא המיובאת כדי לעטוף את האפליקציה, ורכיבי Material 3 משתמשים בתפקידי צבע ברירת המחדל.

לפני שמתחילים להוסיף צבעים לאפליקציה, כדאי לקרוא על תפקידי הצבעים ועל השימוש בהם.

תפקידי צבע ונגישות

אפשר להשתמש בכל תפקיד צבע במגוון מקומות, בהתאם למצב, לחשיבות ולהדגשה של הרכיב.

1f184a05ea57aa84.png

תפקידי הצבעים הראשי, המשני והשלישוני.

הצבע הראשי הוא צבע הבסיס, שמשמש לרכיבים העיקריים כמו כפתורים בולטים ומצבים פעילים.

צבע המפתח המשני משמש לרכיבים פחות בולטים בממשק המשתמש, כמו צ'יפים של מסננים.

צבע המפתח השלישי משמש להדגשות מנוגדות, וצבעים ניטרליים משמשים לרקע ולמשטחים באפליקציה.

מערכת הצבעים של Material מספקת ערכי גוון ומדידות סטנדרטיים שאפשר להשתמש בהם כדי לעמוד ביחסי ניגודיות נגישים. כדי לספק ניגודיות נגישה למשתמש, כדאי להשתמש בצבעים on-primary על גבי צבעים primary, בצבעים on-primary-container על גבי צבעים primary-container, וכך גם לגבי צבעים משניים וניטרליים אחרים.

מידע נוסף זמין במאמר בנושא תפקידי צבע ונגישות.

הגבהות טונאליות ושל אזורים כהים

ב-Material 3, הגובה מיוצג בעיקר באמצעות שכבות-על של צבעים טונאליים. זו דרך חדשה להבדיל בין מאגרי תגים ובין משטחים שונים – הגדלת הניגודיות יוצרת טון בולט יותר – בנוסף לשימוש בצלליות.

הגבהה טונאלית עם הגבהה מוצללת הגבהה טונאלית ברמה 2, שמשתמשת בצבע מתוך משבצת הצבע הראשי.

גם שכבות העל של הגובה בעיצובים כהים השתנו לשכבות על של צבעים טונאליים ב-Material Design 3. צבע השכבה השקופה מגיע ממשבצת הצבע הראשי.

‫M3 Surface – רכיב הבסיס הקומפוזבילי שמאחורי רוב רכיבי M3 – כולל תמיכה בהדגשה של גוונים וצללים:

Surface(
   modifier = modifier,
   tonalElevation = {..}
   shadowElevation = {..}
) {
   Column(content = content)
}

הוספת צבעים לאפליקציה

אם מריצים את האפליקציה, אפשר לראות את הצבעים המיוצאים באפליקציה במקומות שבהם הרכיבים מקבלים צבעי ברירת מחדל. עכשיו, אחרי שהבנו מהם תפקידי הצבעים ואיך משתמשים בהם, נחיל על האפליקציה עיצוב עם תפקידי הצבעים הנכונים.

be7a661b4553167b.png

אפליקציה עם ערכת צבעים ורכיבים שמשתמשים בתפקידי צבע ברירת מחדל.

צבעי המשטח

במסך הבית, מתחילים בהוספת Surface() סביב רכיב ה-Composable הראשי של האפליקציה כדי לספק את הבסיס למיקום התוכן של האפליקציה מעליו. פותחים את MainActivity.kt ועוטפים את הקומפוזיציה ReplyApp() באמצעות Surface.

תצטרכו גם לספק גובה טונאלי של 5dp כדי לתת לרקע צבע טונאלי של משבצת ראשית, שיעזור ליצור ניגודיות ביחס לפריט ברשימה ולסרגל החיפוש שמעליו. כברירת מחדל, הגובה הטונאלי והצללי של המשטח הוא 0.dp.

MainActivity.kt

AppTheme {
   Surface(tonalElevation = 5.dp) {
       ReplyApp(
           replyHomeUIState = uiState,
          // other parameters
         )
   }
}

אם מריצים את האפליקציה עכשיו ורואים גם את רשימת הפריטים וגם את דף הפרטים, אמור להיות לכם ברור שהשכבה הטונאלית הוחלה על כל האפליקציה.

be7a661b4553167b.png e70d762495173610.png

רקע האפליקציה ללא צבע משטח וצבע טונאלי (מימין).

רקע האפליקציה עם צבע משטח וצבע טונאלי (מימין).

הצבעים של סרגל האפליקציה

סרגל החיפוש המותאם אישית בחלק העליון לא כולל רקע שקוף, כפי שנדרש בעיצוב. כברירת מחדל, המערכת חוזרת אל משטח הבסיס שמוגדר כברירת מחדל. אפשר להוסיף רקע כדי ליצור הפרדה ברורה.

5779fc399d8a8187.png

סרגל חיפוש מותאם אישית ללא רקע (מימין).

סרגל חיפוש מותאם אישית עם רקע (מימין).

עכשיו עורכים את ui/components/ReplyAppBars.kt, שמכיל את סרגל האפליקציות. תוסיף MaterialTheme.colorScheme.background ל-Modifier של Row Composable.

ReplyAppBars.kt

@Composable
fun ReplySearchBar(modifier: Modifier = Modifier) {
   Row(
       modifier = modifier
           .fillMaxWidth()
           .padding(16.dp)
           .background(MaterialTheme.colorScheme.background),
       verticalAlignment = Alignment.CenterVertically
   ) {
       // Search bar content
   }
}

עכשיו אמור להיות הפרדה ברורה בין משטח הגוונים לבין סרגל האפליקציות עם צבע הרקע.

b1b374b801dadc06.png

סרגל חיפוש עם צבע רקע מעל משטח טונאלי.

צבעים של כפתור פעולה צף (FAB)

70ceac87233fe466.png

FAB גדול בלי ערכת נושא (משמאל).

לחצן פעולה צף גדול עם צבע משני (מימין).

במסך הבית, אתם יכולים לשפר את המראה של כפתור הפעולה הצף (FAB) כדי שהוא יבלוט ככפתור קריאה לפעולה. כדי להטמיע את זה, צריך להחיל עליו צבע משני להדגשה.

בקובץ ReplyListContent.kt מעדכנים את containerColor של ה-FAB ל-tertiaryContainer ואת צבע התוכן ל-onTertiaryContainer כדי לשמור על הנגישות ועל ניגודיות הצבעים.

ReplyListContent.kt

ReplyInboxScreen(/*..*/) {
// Email list content
  LargeFloatingActionButton(
    containerColor = MaterialTheme.colorScheme.tertiaryContainer,
    contentColor = MaterialTheme.colorScheme.onTertiaryContainer
  ){
   /*..*/   
  }
}

מריצים את האפליקציה כדי לראות את ה-FAB עם העיצוב החדש. ב-Codelab הזה משתמשים ב-LargeFloatingActionButton.

צבעי הכרטיסים

רשימת כתובות האימייל במסך הבית משתמשת ברכיב כרטיס. כברירת מחדל, זהו כרטיס מלא שמשתמש בצבע וריאציה של משטח לצבע המאגר, כדי ליצור הפרדה ברורה בין צבע המשטח לצבע הכרטיס. ‫Compose מספק גם הטמעות של ElevatedCard ושל OutlinedCard.

כדי להדגיש עוד יותר פריטים חשובים, אפשר לספק גוונים משניים של צבע. תשנו את ui/components/ReplyEmailListItem.kt על ידי עדכון הצבע של מאגר הכרטיסים באמצעות CardDefaults.cardColors() באימיילים חשובים:

ReplyEmailListItem.kt

Card(
   modifier =  modifier
       .padding(horizontal = 16.dp, vertical = 4.dp)
       .semantics { selected = isSelected }
       .clickable { navigateToDetail(email.id) },
   colors = CardDefaults.cardColors(
       containerColor = if (email.isImportant)
           MaterialTheme.colorScheme.secondaryContainer
       else MaterialTheme.colorScheme.surfaceVariant
   )
){
  /*..*/   
}

5818200be0b01583.png 9367d40023db371d.png

הדגשת פריט ברשימה באמצעות צבע משני של מאגר בצבעים שונים.

צבע של פריט ברשימת פרטים

עכשיו יש לכם ערכת נושא במסך הבית. כדי לראות את דף הפרטים, לוחצים על אחד מהפריטים ברשימת כתובות האימייל.

7a9ea7cf3e91e9c7.png 79b3874aeca4cd1.png

דף פרטים שמוגדר כברירת מחדל ללא פריט ברשימה עם עיצוב (משמאל).

פריט ברשימת פרטים עם רקע של ערכת נושא (מימין).

לא הוחל צבע על פריט הרשימה, ולכן המערכת חוזרת לצבע ברירת המחדל של המשטח. תחיל צבע רקע על פריט הרשימה כדי ליצור הפרדה, ותוסיף ריווח פנימי כדי ליצור מרווחים מסביב לרקע.

ReplyEmailThreadItem.kt

@Composable
fun ReplyEmailThreadItem(
   email: Email,
   modifier: Modifier = Modifier
) {
   Column(
       modifier = modifier
           .fillMaxWidth()
           .padding(16.dp)
           .background(MaterialTheme.colorScheme.background)
           .padding(20.dp)
    ) {
      // List item content
    }
}

אפשר לראות שרק על ידי הוספת רקע, נוצר הפרדה ברורה בין משטח הצבע לבין פריט הרשימה.

עכשיו יש לכם דף בית ודף פרטים עם תפקידי צבעים ושימוש נכונים . נראה איך אפשר להשתמש בצבעים דינמיים באפליקציה כדי לספק חוויה מותאמת אישית ועקבית יותר.

5. הוספת צבעים דינמיים באפליקציה

צבעים דינמיים הם חלק מרכזי ב-Material 3. אלגוריתם גוזר צבעים בהתאמה אישית מטפט של משתמש כדי להחיל אותם על האפליקציות וממשק המשתמש של המערכת.

התאמה דינמית של ערכות נושא מאפשרת לכם להתאים אישית את האפליקציות. בנוסף, הוא מספק למשתמשים חוויה עקבית וחלקה עם ערכת הנושא של המערכת.

התכונה 'צבע דינמי' זמינה ב-Android מגרסה 12 ואילך. אם האפשרות 'צבע דינמי' זמינה, אפשר להגדיר ערכת צבעים דינמית באמצעות dynamicDarkColorScheme() או dynamicLightColorScheme(). אם לא, צריך לחזור לשימוש בColorScheme בהיר או כהה שמוגדר כברירת מחדל.

מחליפים את הקוד של הפונקציה AppTheme בקובץ Theme.kt בקוד שבהמשך:

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean =  isSystemInDarkTheme(),
   content: @Composable () -> Unit
) {
   val context = LocalContext.current
   val colors = when {
       (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) -> {
           if (useDarkTheme) dynamicDarkColorScheme(context)
           else dynamicLightColorScheme(context)
       }
       useDarkTheme -> DarkColors
       else -> LightColors
   }
   
      MaterialTheme(
       colorScheme = colors,
       content = content
     )
}

fecc63b4c6034236.png

עיצוב דינמי שנלקח מהטפט של Android 13.

כשמריצים את האפליקציה עכשיו, אמור להיות מוחל עליה עיצוב דינמי באמצעות טפט ברירת המחדל של Android 13.

יכול להיות שתרצו גם ששורת הסטטוס תעוצב באופן דינמי בהתאם לערכת הצבעים המשמשת לעיצוב האפליקציה.

1095e2b2c1ffdc14.png

אפליקציה ללא צבע בשורת הסטטוס (משמאל).

אפליקציה עם צבע שורת הסטטוס (מימין).

כדי לעדכן את צבע שורת הסטטוס בהתאם לצבע הראשי של העיצוב, מוסיפים את צבע שורת הסטטוס אחרי בחירת ערכת הצבעים ב-AppTheme composable:

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean =  isSystemInDarkTheme(),
   content: @Composable () -> Unit
) {
 
 // color scheme selection code

 // Add primary status bar color from chosen color scheme.
 val view = LocalView.current
 if (!view.isInEditMode) {
    SideEffect {
        val window = (view.context as Activity).window
        window.statusBarColor = colors.primary.toArgb()
        WindowCompat
            .getInsetsController(window, view)
            .isAppearanceLightStatusBars = useDarkTheme
    }
 }
   
  MaterialTheme(
    colorScheme = colors,
     content = content
   )
}

כשמריצים את האפליקציה, שורת הסטטוס אמורה לקבל את הצבע הראשי של העיצוב. אפשר גם לנסות עיצובים דינמיים בהירים וכהים על ידי שינוי העיצוב הכהה של המערכת.

69093b5bce31fd43.png

עיצוב בהיר דינמי (משמאל) ועיצוב כהה דינמי (מימין) שמוחל עם טפט ברירת המחדל של Android 13.

עד עכשיו, החלת צבעים על האפליקציה שלך שיפרו את המראה שלה. עם זאת, אפשר לראות שכל הטקסט באפליקציה הוא באותו גודל, ולכן אפשר להוסיף לאפליקציה טיפוגרפיה.

6. טיפוגרפיה

ב-Material Design 3 מוגדר קנה מידה של סוגים. השמות והקיבוץ פושטו: display (תצוגה), headline (כותרת ראשית), title (כותרת), body (גוף) ו-label (תווית), עם גדלים גדולים, בינוניים וקטנים לכל אחד מהם.

999a161dcd9b0ec4.png

סולם סוגים של Material 3.

הגדרת טיפוגרפיה

‫Compose מספקת את המחלקה M3 Typography – בנוסף למחלקות הקיימות TextStyle ו- font-related – כדי ליצור מודל של סולם הסוגים של Material 3.

הקונסטרוקטור Typography מציע ערכי ברירת מחדל לכל סגנון, כך שאפשר להשמיט פרמטרים שלא רוצים להתאים אישית. מידע נוסף זמין במאמר בנושא סגנונות טיפוגרפיה וערכי ברירת המחדל שלהם.

באפליקציה שלך נעשה שימוש בחמישה סגנונות טיפוגרפיים: headlineSmall, titleLarge, bodyLarge, bodyMedium ו-labelMedium. הסגנונות האלה יחולו גם על מסך הבית וגם על מסך הפרטים.

מסך שמציג את השימוש בטיפוגרפיה של כותרת, תווית וסגנון גוף.

מסך שבו מוצג שימוש בטיפוגרפיה של כותרת, תווית וסגנון גוף.

לאחר מכן, עוברים לחבילה ui/theme ופותחים את Type.kt. כדי לספק הטמעה משלכם לחלק מסגנונות הטקסט במקום ערכי ברירת המחדל, מוסיפים את הקוד הבא:

Type.kt

val typography = Typography(
   headlineSmall = TextStyle(
       fontWeight = FontWeight.SemiBold,
       fontSize = 24.sp,
       lineHeight = 32.sp,
       letterSpacing = 0.sp
   ),
   titleLarge = TextStyle(
       fontWeight = FontWeight.Normal,
       fontSize = 18.sp,
       lineHeight = 28.sp,
       letterSpacing = 0.sp
   ),
   bodyLarge = TextStyle(
       fontWeight = FontWeight.Normal,
       fontSize = 16.sp,
       lineHeight = 24.sp,
       letterSpacing = 0.15.sp
   ),
   bodyMedium = TextStyle(
       fontWeight = FontWeight.Medium,
       fontSize = 14.sp,
       lineHeight = 20.sp,
       letterSpacing = 0.25.sp
   ),
   labelMedium = TextStyle(
       fontWeight = FontWeight.SemiBold,
       fontSize = 12.sp,
       lineHeight = 16.sp,
       letterSpacing = 0.5.sp
   )
)

הגדרתם עכשיו את הטיפוגרפיה. כדי להוסיף אותו לעיצוב, מעבירים אותו לרכיב MaterialTheme() composable בתוך AppTheme:

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean = isSystemInDarkTheme(),
   content: @Composable() () -> Unit
) {
  // dynamic theming content

   MaterialTheme(
       colorScheme = colors,
       typography = typography,
       content = content
   )
}

עבודה עם טיפוגרפיה

בדומה לצבעים, אפשר לגשת לסגנון הטיפוגרפיה של העיצוב הנוכחי באמצעות MaterialTheme.typography. כך מקבלים את מופע הטיפוגרפיה לשימוש בכל הטיפוגרפיה שהוגדרה ב-Type.kt.

Text(
   text = "Hello M3 theming",
   style = MaterialTheme.typography.titleLarge
)

Text(
   text = "you are learning typography",
   style = MaterialTheme.typography.bodyMedium
)

סביר להניח שלא תצטרכו את כל 15 סגנונות ברירת המחדל מסולם הטיפוגרפיה של Material Design. ב-codelab הזה נבחרו חמישה גדלים, והשאר הושמטו.

מכיוון שלא החלתם טיפוגרפיה על רכיבי ה-Composable‏ (Text(), כל הטקסט חוזר ל-Typography.bodyLarge כברירת מחדל.

טיפוגרפיה של רשימת הבית

לאחר מכן, מחילים טיפוגרפיה על הפונקציה ReplyEmailListItem ב-ui/components/ReplyEmailListItem.kt כדי ליצור הבחנה בין כותרות לתוויות:

ReplyEmailListItem.kt

Text(
   text = email.sender.firstName,
   style = MaterialTheme.typography.labelMedium
)

Text(
   text = email.createdAt,
   style = MaterialTheme.typography.labelMedium
)

Text(
   text = email.subject,
   style = MaterialTheme.typography.titleLarge,
   modifier = Modifier.padding(top = 12.dp, bottom = 8.dp),
)

Text(
   text = email.body,
   maxLines = 2,
   style = MaterialTheme.typography.bodyLarge,
   overflow = TextOverflow.Ellipsis
)

90645c0765167bb7.png 6c4af2f412c18bfb.png

מסך הבית בלי טיפוגרפיה (מימין).

מסך הבית עם טיפוגרפיה (מימין).

טיפוגרפיה של רשימת פרטים

באופן דומה, תוסיפו את הטיפוגרפיה במסך הפרטים על ידי עדכון כל רכיבי הטקסט של ReplyEmailThreadItem ב-ui/components/ReplyEmailThreadItem.kt:

ReplyEmailThreadItem.kt

Text(
   text = email.sender.firstName,
   style = MaterialTheme.typography.labelMedium
)

Text(
   text = stringResource(id = R.string.twenty_mins_ago),
   style = MaterialTheme.typography.labelMedium
)

Text(
   text = email.subject,
   style = MaterialTheme.typography.bodyMedium,
   modifier = Modifier.padding(top = 12.dp, bottom = 8.dp),
)

Text(
   text = email.body,
   style = MaterialTheme.typography.bodyLarge,
   color = MaterialTheme.colorScheme.onSurfaceVariant
)

543ac09e43d8761.png 3412771e95a45f36.png

מסך פרטים בלי טיפוגרפיה (מימין).

מסך פרטים עם טיפוגרפיה (מימין).

התאמה אישית של הטיפוגרפיה

בעזרת התכונה 'יצירת הודעה', קל מאוד להתאים אישית את סגנון הטקסט או לספק גופן בהתאמה אישית. אפשר לשנות את TextStyle כדי להתאים אישית את סוג הגופן, משפחת הגופנים, הריווח בין האותיות וכו'.

תשנו את סגנון הטקסט בקובץ theme/Type.kt, והשינוי ישתקף בכל הרכיבים שמשתמשים בו.

מעדכנים את fontWeight ל-SemiBold ואת lineHeight ל-32.sp עבור titleLarge, שמשמש כנושא בפריט הרשימה. ההדגשה תהיה חזקה יותר וההפרדה תהיה ברורה יותר.

Type.kt

...
titleLarge = TextStyle(
   fontWeight = FontWeight.SemiBold,
   fontSize = 18.sp,
   lineHeight = 32.sp,
   letterSpacing = 0.0.sp
),
...

f8d2212819eb0b61.png

החלת טיפוגרפיה מותאמת אישית על טקסט הנושא.

7. צורות

משטחי Material יכולים להופיע בצורות שונות. צורות מכוונות את תשומת הלב, מזהות רכיבים, מעבירות מידע על מצב ומבטאות את המותג.

הגדרת צורות

הכיתה Shapes מספקת פרמטרים מורחבים להטמעה של צורות M3 חדשות. סולם הצורות M3, בדומה לסולם הסוגים, מאפשר מגוון רחב של צורות בממשק המשתמש.

יש גדלים שונים של צורות בסולם הצורות:

  • קטן במיוחד
  • קטן
  • בינונית
  • גדול
  • גדול מאוד

כברירת מחדל, לכל צורה סגורה יש ערך ברירת מחדל שאפשר לשנות. באפליקציה שלכם, תשתמשו בצורה הבינונית כדי לשנות את הפריט ברשימה, אבל אתם יכולים להגדיר גם צורות אחרות. יוצרים קובץ חדש בשם Shape.kt בחבילה ui/theme ומוסיפים את הקוד לצורות:

Shape.kt

package com.example.reply.ui.theme

import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp

val shapes = Shapes(
   extraSmall = RoundedCornerShape(4.dp),
   small = RoundedCornerShape(8.dp),
   medium = RoundedCornerShape(16.dp),
   large = RoundedCornerShape(24.dp),
   extraLarge = RoundedCornerShape(32.dp)
)

אחרי שמגדירים את shapes, מעבירים אותו אל MaterialTheme M3 כמו שעשיתם לגבי הצבעים והטיפוגרפיה:

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean = isSystemInDarkTheme(),
   content: @Composable() () -> Unit
) {
  // dynamic theming content

   MaterialTheme(
       colorScheme = colors,
       typography = typography,
       shapes = shapes
       content = content
   )
}

עבודה עם צורות

בדומה לצבע ולטיפוגרפיה, אפשר להחיל צורות על רכיבי Material באמצעות MaterialTheme.shape, וכך לקבל את מופע Shape כדי לגשת לצורות Material.

להרבה רכיבי Material כבר מוגדרים צורות ברירת מחדל, אבל אתם יכולים לספק ולהחיל צורות משלכם על רכיבים באמצעות משבצות זמינות.

Card(shape = MaterialTheme.shapes.medium) { /* card content */ }
FloatingActionButton(shape = MaterialTheme.shapes.large) { /* fab content */}

ערכי ברירת מחדל של צורות לכל רכיבי Material 3.מיפוי של רכיבי Material באמצעות סוגים שונים של צורות.

במסמכי התיעוד בנושא צורות אפשר לראות את המיפוי של הצורות לכל הרכיבים.

יש עוד שתי צורות שאפשר להשתמש בהן – RectangleShape ו-CircleShape – שהן חלק מהתכונה 'יצירה'. לצורה המלבנית אין רדיוס גבול, ולצורה העגולה יש קצוות מעוגלים מלאים.

אפשר גם להחיל צורה על רכיבים באמצעות Modifiers שמקבלים צורות, כמו Modifier.clip, Modifier.background ו- Modifier.border.

הצורה של סרגל האפליקציה

אנחנו רוצים שסרגל האפליקציה יהיה עם רקע פינתי מעוגל:

f873392abe535494.png

האפליקציה TopAppBar משתמשת בRow עם צבע רקע. כדי ליצור רקע עם פינות מעוגלות, צריך להגדיר את צורת הרקע באמצעות העברת CircleShape לשינוי הרקע:

ReplyAppBars.kt

@Composable
fun ReplySearchBar(modifier: Modifier = Modifier) {
   Row(
       modifier = modifier
           .fillMaxWidth()
           .padding(16.dp)
           .background(
               MaterialTheme.colorScheme.background,
               CircleShape
           ),
       verticalAlignment = Alignment.CenterVertically
   ) {
       // Search bar content
   }
}

f873392abe535494.png

צורה של פריט ברשימת פרטים

במסך הבית, אתם משתמשים בכרטיס שמוגדר כברירת מחדל עם Shape.Medium. עם זאת, בדף הפרטים השתמשתם בעמודה עם צבע רקע. כדי שהרשימה תיראה אחידה, אפשר להחיל עליה צורה בינונית.

3412771e95a45f36.png 80ee881c41a98c2a.png

עמודה של פריט ברשימה מפורטת ללא צורה בפריט ברשימה (משמאל) וצורה בינונית ברשימה (מימין).

ReplyEmailThreadItem.kt

@Composable
fun ReplyEmailThreadItem(
   email: Email,
   modifier: Modifier = Modifier
) {
   Column(
       modifier = modifier
           .fillMaxWidth()
           .padding(8.dp)
           .background(
               MaterialTheme.colorScheme.background,
               MaterialTheme.shapes.medium
           )
           .padding(16.dp)

   ) {
      // List item content
      
   }
}

עכשיו, כשמריצים את האפליקציה, מוצג פריט מפורט ברשימת המסכים בצורה של medium.

8. הדגשה

ההדגשה בממשק המשתמש עוזרת להבליט תוכן מסוים על פני תוכן אחר, למשל כשרוצים להבדיל בין שם הסרט לבין הכתוביות. ההדגשה ב-M3 מתבססת על וריאציות של צבע ושילובים של צבעים. יש שתי דרכים להדגיש טקסט:

  1. שימוש בצבעים של משטח, וריאציה של משטח ורקע לצד צבעים של טקסט על משטח ווריאציות של טקסט על משטח ממערכת הצבעים המורחבת של M3.

לדוגמה, אפשר להשתמש ב-surface עם on-surface-variant, וב-surface-variant עם on-surface כדי להדגיש את הטקסט ברמות שונות.

אפשר גם להשתמש בווריאציות של צבעי הרקע עם צבעי הדגשה כדי להשיג פחות הדגשה מאשר עם צבעי הדגשה רגילים, אבל עדיין לשמור על נגישות ולעמוד ביחס הניגודיות.

תפקידי הצבע Surface,‏ Background ו-Surface variant.

תפקידי הצבע של המשטח, הרקע ווריאנט המשטח.

  1. שימוש במשקלים שונים של גופנים לטקסט. כפי שראיתם בקטע על טיפוגרפיה, אתם יכולים לספק משקלים מותאמים אישית לסולם הטיפוגרפי כדי להדגיש דברים שונים.

לאחר מכן, מעדכנים את ReplyEmailListItem.kt כדי להבליט את ההבדל באמצעות וריאציית המשטח. כברירת מחדל, צבע התוכן בכרטיס הוא צבע ברירת המחדל של התוכן, בהתאם לרקע.

תעדכנו את הצבע של הטקסט של השעה ושל הטקסט של גוף ההודעה ל-onSurfaceVariant. כך ההדגשה שלו פחותה בהשוואה ל-onContainerColors, שמוחל על רכיבי טקסט של נושא וכותרת כברירת מחדל.

2c9b7f2bd016edb8.png 6850ff391f21e4ba.png

השעה וטקסט הגוף עם אותו דגש בהשוואה לנושא ולכותרת (משמאל).

השעה והתוכן עם דגש מופחת בהשוואה לנושא ולכותרת (מימין).

ReplyEmailListItem.kt

Text(
   text = email.createdAt,
   style = MaterialTheme.typography.labelMedium,
   color = MaterialTheme.colorScheme.onSurfaceVariant
)

Text(
   text = email.body,
   maxLines = 2,
   style = MaterialTheme.typography.bodyLarge,
   color = MaterialTheme.colorScheme.onSurfaceVariant
   overflow = TextOverflow.Ellipsis
)

בכרטיס של האימייל החשוב עם הרקע secondaryContainer, צבע הטקסט הוא onSecondaryContainer כברירת מחדל. בשאר האימיילים, הרקע הוא surfaceVariant, ולכן כל הטקסט מוגדר כברירת מחדל לצבע onSurfaceVariant.

9. מזל טוב

מעולה! סיימתם בהצלחה את ה-Codelab הזה! הטמעתם עיצוב Material באמצעות Compose, עם צבעים, טיפוגרפיה וצורות, וגם צבעים דינמיים כדי לעצב את האפליקציה ולספק חוויה מותאמת אישית.

2d8fcabf15ac5202.png 5a4d31db0185dca6.png ce009e4ce560834d.png

סוף התוצאות של העיצוב עם צבעים דינמיים וערכת צבעים שהוחלו.

המאמרים הבאים

כדאי לעיין ב-Codelabs אחרים שלנו בנושא Compose:

קריאה נוספת

אפליקציות לדוגמה

  • אפליקציית Reply sample עם ערכת נושא מלאה של Material 3
  • JetChat שמדגים שימוש בערכות נושא דינמיות

מסמכי עזר