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

1. מבוא

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

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

מה תלמדו

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

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

מה תפַתחו

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

d15db3dc75a9d00f.png

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

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

1357cdbfaaa67721.png

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

1357cdbfaaa67721.png

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

מה צריך להכין

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

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

קבל את הקוד

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

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

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

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

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

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

בחינת קוד ההתחלה

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

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

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

3. עיצוב של Material 3

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

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

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

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

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

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

חמישה צבעי מפתח בסיסיים ליצירת עיצוב M3.

חמישה צבעי מפתח בסיסיים ליצירת עיצוב M3.

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

ארבעה צבעי טונל של צבעי בסיס: ראשוני, משני ושלישי.

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

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

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

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

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

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

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

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

294f73fc9d2a570e.png

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

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

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

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

הצבע הראשי #825500 יוצר את העיצוב הבא שצריך להוסיף לאפליקציה. חומר 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.

כוללים את התוכן הקומפוזבילי 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
   )
}

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

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

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

כדי להחיל את העיצוב החדש, ב-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 תומך בערכות צבעים בהירים וגם בגוונים כהים. יש לך רק את האפליקציה עם העיצוב המיובא. רכיבי חומר 3 משתמשים בתפקידי צבע שמוגדרים כברירת מחדל.

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

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

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

1f184a05ea57aa84.png

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

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

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

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

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

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

גובה טונלי וצללים

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

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

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

המשטח M3 – התוכן הקומפוזבילי לגיבוי מאחורי רוב רכיבי M3 – כולל תמיכה בהגבהה טונלית ובגובה של מספר האזורים הכהים:

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

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

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

be7a661b4553167b.png

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

צבעי פני השטח

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

תספק גם גובה טונלי של 5.dp כדי לתת למשטח צבע טונלי של משבצת ראשית, כדי ליצור ניגודיות בין הפריט ברשימה לבין סרגל החיפוש שמעליו. כברירת מחדל, גובה הגוון והצל של פני השטח הוא 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.

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

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

צבעים של לחצני פעולה צפים

70ceac87233fe466.png

FAB גדול ללא עיצוב נושא (שמאל).

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.

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

רשימת כתובות האימייל במסך הבית משתמשת ברכיב של כרטיס. כברירת מחדל, זהו כרטיס עם מילוי שהצבע של המשטח בו משתנה בהתאם לצבע המשטח, כדי לאפשר הפרדה ברורה בין המשטח לצבע הכרטיס. ההצעות לכתיבה כוללות גם הטמעות של 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. הוספת צבעים דינמיים באפליקציה

צבע דינמי הוא החלק המרכזי של חומר 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:

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 מגדיר סולם סוגים. השמות והחלוקה לקבוצות פשוטים יותר למטרות הבאות: תצוגה, כותרת, כותרת, גוף ותווית, כשכל אחד מהם גדול, בינוני וקטן.

999a161dcd9b0ec4.png

קנה מידה של חומר 3.

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

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

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

ניתן להשתמש בחמישה סגנונות טיפוגרפיה באפליקציה: 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() בתוך 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.k t.

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

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

סביר להניח שלא יהיה צורך בכל 15 סגנונות ברירת המחדל של המוצר מסולם הסוגים 'עיצוב חומר'. ב-Codelab הזה נבחרים חמישה גדלים והשאר מושמט.

בגלל שלא החלת טיפוגרפיה על התכנים הקומפוזביליים 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. צורות

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

הגדרת צורות

הכתיבה מספקת למחלקה 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.

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

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

תפקידים של צבעי 'שטח', 'רקע' ו'משטח'.

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

  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 הזה! הטמעתם עיצוב Materials עם 'כתיבה' באמצעות צבעים, טיפוגרפיה וצורות יחד עם צבעים דינמיים כדי לעצב את האפליקציה שלכם ולספק חוויה מותאמת אישית.

2d8fcabf15ac5202.png 5a4d31db0185dca6.png ce009e4ce560834d.png

סוף תוצאות העיצוב, עם צבעים דינמיים ועיצוב צבעים.

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

אתם מוזמנים לנסות את שיעורי Lab הנוספים שלנו שמופיעים במסלול 'כתיבה':

קריאה נוספת

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

מסמכי עזר