פיתוח אפליקציה מלאה באמצעות Relay ו-Jetpack Compose

1. לפני שמתחילים

Relay הוא ערכת כלים שמאפשרת לצוותים לעצב רכיבי ממשק משתמש ב-Figma ולהשתמש בהם ישירות בפרויקטים של Jetpack Compose. הכלי הזה מבטל את הצורך במחזור מייגע של מפרטים ועיצובים ובקרת איכות, וכך עוזר לצוותים לספק ממשקי משתמש מעולים ל-Android במהירות.

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

דרישות מוקדמות

  • ניסיון בסיסי ב-Compose. אם עדיין לא עשיתם זאת, מומלץ להשלים את קורס ה-codelab בנושא יסודות של Jetpack Compose.
  • ניסיון בתחביר Kotlin.

מה תלמדו

  • איך מייבאים חבילות ממשק משתמש.
  • איך משלבים חבילות ממשק משתמש עם ארכיטקטורת ניווט ונתונים.
  • איך עוטפים חבילות ממשק משתמש בלוגיקה של בקר.
  • איך ממפים סגנונות של Figma לעיצוב של Compose.
  • איך מחליפים חבילות UI ברכיבים מורכבים קיימים בקוד שנוצר.

מה תפַתחו

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

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

מה צריך להכין

2. להגדרה

קבלת הקוד

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

$ git clone https://github.com/googlecodelabs/relay-codelabs
  • עוברים אל המאגר relay-codelabs ב-GitHub, בוחרים את ההסתעפות הרצויה ולוחצים על Code > Download zip (קוד > הורדת קובץ zip) ופורקים את קובץ ה-zip שהורדתם.

בכל מקרה, ההסתעפות main מכילה את קוד ההתחלה וההסתעפות end מכילה את קוד הפתרון.

התקנת הפלאגין Relay for Android Studio

אם עדיין אין לכם את הפלאגין Relay for Android Studio, עליכם לפעול לפי השלבים הבאים:

  1. ב-Android Studio, לוחצים על הגדרות > יישומי פלאגין.
  2. בתיבת הטקסט, מזינים Relay for Android Studio.
  3. לוחצים על התקנה בתוסף שמופיע בתוצאות החיפוש.

הגדרות הפלאגין של Android Studio

  1. אם מופיעה תיבת הדו-שיח הערה בנושא פרטיות של יישומי פלאגין של צד שלישי, לוחצים על אישור.
  2. לוחצים על אישור > הפעלה מחדש.
  3. אם מופיעה תיבת הדו-שיח Confirm exit, לוחצים על Exit.

חיבור Android Studio ל-Figma

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

אם עדיין לא קישרתם את Android Studio ל-Figma, עליכם לבצע את השלבים הבאים:

  1. בחשבון Figma, לוחצים על סמל הפרופיל בחלק העליון של הדף ובוחרים באפשרות הגדרות.
  2. בקטע אסימוני גישה אישיים, מזינים תיאור של האסימון בתיבת הטקסט ומקישים על Enter (או על return ב-macOS). נוצר טוקן.
  3. לוחצים על העתקת האסימון.

אסימון גישה שנוצר ב-Figma

  1. ב-Android Studio, בוחרים באפשרות Tools (כלים) > Relay Settings (הגדרות העברה). תיבת הדו-שיח Relay settings מופיעה.
  2. מדביקים את אסימון הגישה בתיבת הטקסט Figma Access Token ולוחצים על OK. הסביבה מוגדרת.

3. בדיקת העיצוב של האפליקציה

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

בדיקת מסך הבית

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

מסך הבית

ב-Figma, המעצב שלנו חילק את המסך הזה למספר רכיבים, הגדיר את ממשקי ה-API שלהם וחביל אותם באמצעות הפלאגין Relay for Figma. אחרי האריזה של הרכיבים האלה, אפשר לייבא אותם לפרויקט ב-Android Studio.

רכיב של מסך הבית

בודקים את מסך ההוספה/העריכה

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

מסך ההוספה/העריכה

באופן דומה, המסך הזה מחולק למספר רכיבים ארוזים.

הוספה או עריכה של רכיבי המסך

בדיקת העיצוב

הצבעים והטיפוגרפיה של העיצוב הזה מוטמעים כסגנונות של Figma על סמך שמות של אסימונים של Material Design 3. כך אפשר לשפר את יכולת הפעולה ההדדית עם נושאים של Compose ורכיבי Material.

סגנונות של Figma

4. ייבוא חבילות ממשק משתמש

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

כדי לקבל את הקישור למקור ב-Figma:

  1. ב-Figma, לוחצים על ייבוא קובץ ובוחרים את הקובץ ReflectDesign.fig שנמצא בתיקיית הפרויקט CompleteAppCodelab.
  2. לוחצים לחיצה ימנית על הקובץ ובוחרים באפשרות העתקת הקישור. תצטרכו אותו בקטע הבא.

88afd168463bf7e5.png

ייבוא חבילות של ממשק משתמש לפרויקט

  1. פותחים את הפרויקט ./CompleteAppCodelab ב-Android Studio.
  2. לוחצים על קובץ > חדש > ייבוא חבילות ממשק משתמש. תופיע תיבת הדו-שיח Import UI Packages.
  3. בתיבת הטקסט כתובת ה-URL של המקור ב-Figma, מדביקים את כתובת ה-URL שהועתקה בקטע הקודם.

f75d0c3e17b6f75.png

  1. בתיבת הטקסט App theme (עיצוב האפליקציה), מזינים com.google.relay.example.reflect.ui.theme.ReflectTheme. כך תוכלו לוודא שהתצוגות המקדימות שנוצרות ישתמשו בעיצוב המותאם אישית.
  2. לוחצים על הבא. תופיע תצוגה מקדימה של חבילות ממשק המשתמש של הקובץ.
  3. לוחצים על יצירה. החבילות מיובאות לפרויקט.
  4. עוברים לכרטיסייה Project ולוחצים על החץ להרחבה 2158ffa7379d2b2e.png לצד התיקייה ui-packages.

התיקייה ui-packages

  1. לוחצים על החץ להרחבה 2158ffa7379d2b2e.png לצד אחת מתיקי החבילה, ומבחינים שהיא מכילה קובץ מקור מסוג JSON ותלות בנכסים.
  2. פותחים את קובץ המקור JSON. מודול Relay מציג תצוגה מקדימה של החבילה ושל ה-API שלה.

a6105146c4cfb47.png

פיתוח ויצירת קוד

  1. בחלק העליון של Android Studio, לוחצים על b3bc77f3c78cac1b.png יצירת פרויקט. הקוד שנוצר לכל חבילה מתווסף לתיקייה java/com.google.relay.example.reflect. הרכיבים המורכבים שנוצרים מכילים את כל פרטי הפריסה והעיצוב מהעיצוב ב-Figma.
  2. פותחים את הקובץ com/google/relay/example/reflect/range/Range.kt.
  3. שימו לב שהמערכת יוצרת תצוגות מקדימות של Compose לכל וריאציה של רכיב. אם צריך, לוחצים על פיצול כדי להציג את הקוד ואת חלון התצוגה המקדימה זה לצד זה.

c0d21ab0622ad550.png

5. שילוב רכיבים

בקטע הזה נבחן לעומק את הקוד שנוצר למעקב אחר המתג.

העיצוב של מכשיר המעקב אחרי המעבר

  1. ב-Android Studio, פותחים את הקובץ com/google/relay/example/reflect/switch/Switch.kt.

Switch.kt (נוצר)

/**
 * This composable was generated from the UI Package 'switch'.
 * Generated code; don't edit directly.
 */
@Composable
fun Switch(
    modifier: Modifier = Modifier,
    isChecked: Boolean = false,
    emoji: String = "",
    title: String = ""
) {
    TopLevel(modifier = modifier) {
        if (isChecked) {
            ActiveOverlay(modifier = Modifier.rowWeight(1.0f).columnWeight(1.0f)) {}
        }
        TopLevelSynth(modifier = Modifier.rowWeight(1.0f)) {
            Label(modifier = Modifier.rowWeight(1.0f)) {
                Emoji(emoji = emoji)
                Title(
                    title = title,
                    modifier = Modifier.rowWeight(1.0f)
                )
            }
            Checkmark {
                if (isChecked) {
                    Icon()
                }
            }
        }
    }
}
  1. חשוב לשים לב לפרטים הבאים:
  • כל פריסה ועיצוב מהעיצוב ב-Figma נוצרים.
  • רכיבי המשנה מחולקים לרכיבים נפרדים שאפשר לשלב.
  • המערכת יוצרת תצוגות מקדימות שניתן לשלב עבור כל הווריאציות של העיצוב.
  • סגנונות הצבעים והטיפוגרפיה מוטמעים בקוד. תתקנו את זה מאוחר יותר.

הכנסת מכשיר המעקב

  1. ב-Android Studio, פותחים את הקובץ java/com/google/relay/example/reflect/ui/components/TrackerControl.kt. הקובץ הזה מספק נתונים ולוגיקה של אינטראקציה למעקב אחר הרגלים.
  2. פיתוח והרצה של האפליקציה באמולטור. בשלב זה, הרכיב הזה מניב נתונים גולמיים מהמודל למעקב.

5d56f8a7065066b7.png

  1. מייבאים את החבילה com.google.relay.example.reflect.switch.Switch לקובץ.
  2. מחליפים את Text(text = trackerData.tracker.toString()) בבלוק when שמסתובב סביב השדה trackerData.tracker.type.
  3. בגוף הבלוק when, קוראים לפונקציה Switch() Composable כשהטיפוס הוא TrackerType.BOOLEAN.

הקוד אמור להיראות כך:

TrackerControl.kt

// TODO: replace with Relay tracker components
when (trackerData.tracker.type) {
    TrackerType.BOOLEAN ->
        Switch(
          title = trackerData.tracker.name,
          emoji = trackerData.tracker.emoji
        )
    else ->
        Text(trackerData.tracker.toString())
}
  1. צריך לבנות מחדש את הפרויקט. עכשיו דף הבית מציג כראוי את הכלי למעקב אחר המרות ב-Switch, כפי שתוכנן עם נתונים בזמן אמת.

4241e78b9f82075b.png

6. הוספת מצב ואינטראקציה

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

אריזה של חבילות ממשק משתמש בפונקציית Composable של בקר

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

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

  1. ב-Android Studio, פותחים את הקובץ java/com/google/relay/example/reflect/ui/components/SwitchControl.kt.
  2. בפונקציה SwitchControl() Composable, מעבירים את הפרמטרים הבאים:
  • trackerData: אובייקט TrackerData
  • modifier: אובייקט עיטור
  • onLongClick: קריאה חוזרת (callback) של אינטראקציה כדי לאפשר לחיצה ארוכה על מכשירי מעקב לצורך עריכה ומחיקה
  1. מוסיפים פונקציית Switch() ומעבירים משתנה combinedClickable כדי לטפל בלחיצה ובלחיצה ארוכה.
  2. העברת ערכים מהאובייקט TrackerData לפונקציה Switch(), כולל השיטה isToggled().

הפונקציה SwitchControl() המושלמת נראית כך:

SwitchControl.kt

package com.google.relay.example.reflect.ui.components

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.relay.example.reflect.model.Tracker
import com.google.relay.example.reflect.model.TrackerData
import com.google.relay.example.reflect.model.TrackerType
import com.google.relay.example.reflect.switch.Switch

/*
 * A component for controlling switch-type trackers.
 *
 * SwitchControl is responsible for providing interaction and state management to the stateless
 * composable [Switch] generated by Relay. [onLongClick] provides a way for callers to supplement
 * the control's intrinsic interactions with, for example, a context menu.
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun SwitchControl(
    trackerData: TrackerData,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
) {
    Switch(
        modifier
            .clip(shape = RoundedCornerShape(size = 32.dp))
            .combinedClickable(onLongClick = onLongClick) {
                trackerData.toggle()
            },
        emoji = trackerData.tracker.emoji,
        title = trackerData.tracker.name,
        isChecked = trackerData.isToggled(),
    )
}

@Preview
@Composable
fun SwitchControllerPreview() {
    val data = TrackerData(
        Tracker(
            emoji = "🍕",
            name = "Ate Pizza",
            type = TrackerType.BOOLEAN
        )
    )
    SwitchControl(data)
}
  1. בקובץ TrackerControl.kt, מסירים את הייבוא של Switch ומחליפים את הפונקציה Switch() בקריאה לפונקציה SwitchControl().
  2. מוסיפים מקרים לקבועים של המונה TrackerType.RANGE ו-TrackerType.COUNT.

בלוק when המלא נראה כך:

TrackerControl.kt

when (trackerData.tracker.type) {
    TrackerType.BOOLEAN ->
        SwitchControl(
            trackerData = trackerData,
            onLongClick = { expanded = true },
        )
    TrackerType.RANGE ->
        RangeControl(
            trackerData = trackerData,
            onLongClick = { expanded = true },
        )
    TrackerType.COUNT ->
        ValueControl(
            trackerData = trackerData,
            onLongClick = { expanded = true },
        )
}
  1. צריך לבנות מחדש את הפרויקט. עכשיו אתם יכולים להציג מכשירי מעקב וליצור איתם אינטראקציה. מסך הבית מוכן.

b23b94f0034243d3.png

7. מיפוי רכיבים קיימים

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

מיפוי של שדה טקסט

התמונה הבאה היא העיצוב של הרכיב Tracker Settings בתיבת הדו-שיח הוספה/עריכה של מכשיר מעקב:

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

המעצב שלנו השתמש ב-ReflectTextField בתכנון, שכבר יש לנו הטמעה שלו בקוד שמבוסס על שדות טקסט של Material Design 3. מערכת Figma לא תומכת בשדות טקסט באופן מקורי, ולכן קוד ברירת המחדל שנוצר על ידי Relay נראה כמו העיצוב בלבד. הוא לא אמצעי בקרה פונקציונלי.

כדי לבדוק את ההטמעה הנוכחית של TrackerSettings:

  1. ב-Android Studio, יוצרים ומריצים את האפליקציה במהדמ.
  2. לוחצים לחיצה ארוכה על שורה של מכשיר מעקב ובוחרים באפשרות עריכה.
  3. מקישים על שדה הטקסט Title ומבחינים שהוא לא מגיב לאינטראקציה.

כדי להחליף את ההטמעה האמיתית של האלמנט הזה, צריך שני דברים: חבילת ממשק משתמש של שדה טקסט וקובץ מיפוי. למזלנו, המעצב שלנו כבר ארז את הרכיבים של מערכת העיצוב שלנו ב-Figma והשתמש ברכיב של שדה טקסט בעיצוב שלו ל-Tracker Settings. כברירת מחדל, חבילת העץ הזו נוצרת כיחס תלות, אבל משתמשים במיפוי רכיבים כדי להחליף אותה.

רכיב Figma לשדה טקסט עם תוסף Relay שכבת-על

יצירת קובץ מיפוי

הפלאגין Relay for Android Studio מספק קיצור דרך ליצירת קובצי מיפוי רכיבים.

כדי ליצור קובץ מיפוי:

  1. ב-Android Studio, לוחצים לחיצה ימנית על חבילת ממשק המשתמש text_field ובוחרים באפשרות Generate mapping file.

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

  1. תוצג תיבת דו-שיח של קובץ מיפוי. מזינים את האפשרויות הבאות:
  • בקטע Target composable, בוחרים באפשרות Use existing composable ומזינים את הערך com.google.relay.example.reflect.ui.components.ReflectTextField
  • בקטע Generated file (קובץ שנוצר), מסמנים את התיבה Generate implementation (יצירת הטמעה) ומבטלים את הסימון של התיבה Generate Compose Preview (יצירת תצוגה מקדימה של Compose).

e776585c3b838b10.png

  1. לוחצים על Generate mapping file. הפקודה הזו תיצור את קובץ המיפוי הבא:

text_field.json

{
  "target": "ReflectTextField",
  "package": "com.google.relay.example.reflect.ui.components",
  "generateImplementation": true,
  "generatePreviews": false,
}

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

  1. צריך לבנות מחדש את הפרויקט.
  2. בקובץ trackersettings/ TrackerSettings.kt, מחפשים את הפונקציה TitleFieldStyleFilledStateEnabledTextConfigurationsInputText() Composable שנוצרה, ומבחינים בכך שהיא כוללת רכיב ReflectTextField שנוצר.

TrackerSettings.kt (generated)

@Composable
fun TitleFieldStyleFilledStateEnabledTextConfigurationsInputText(
    onTitleChanged: (String) -> Unit,
    title: String,
    modifier: Modifier = Modifier
) {
    ReflectTextField(
        onChange = onTitleChanged,
        labelText = "Title",
        leadingIcon = "search",
        trailingIcon = "cancel",
        supportingText = "Supporting text",
        inputText = title,
        state = State.Enabled,
        textConfigurations = TextConfigurations.InputText,
        modifier = modifier.fillMaxWidth(1.0f).requiredHeight(56.0.dp)
    )
}
  1. צריך לבנות מחדש את הפרויקט. עכשיו אפשר לבצע פעולות בשדות של הגדרות המעקב. מסך העריכה הושלם.

8. מיפוי לנושאי Compose

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

תצוגה מקדימה של מסך הבית במצב כהה עם צבעים שגויים

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

1fac916db14929bb.png

יצירת קובץ למיפוי סגנונות

  1. ב-Android Studio, עוברים לספרייה src/main/ui-package-resources ויוצרים ספרייה חדשה בשם style-mappings. בספרייה הזו, יוצרים קובץ figma_styles.json שמכיל את הקוד הבא:

figma_styles.json

{
  "figma": {
    "colors": {
      "Reflect Light/background": "md.sys.color.background",
      "Reflect Dark/background": "md.sys.color.background",
      "Reflect Light/on-background": "md.sys.color.on-background",
      "Reflect Dark/on-background": "md.sys.color.on-background",
      "Reflect Light/surface": "md.sys.color.surface",
      "Reflect Dark/surface": "md.sys.color.surface",
      "Reflect Light/on-surface": "md.sys.color.on-surface",
      "Reflect Dark/on-surface": "md.sys.color.on-surface",
      "Reflect Light/surface-variant": "md.sys.color.surface-variant",
      "Reflect Dark/surface-variant": "md.sys.color.surface-variant",
      "Reflect Light/on-surface-variant": "md.sys.color.on-surface-variant",
      "Reflect Dark/on-surface-variant": "md.sys.color.on-surface-variant",
      "Reflect Light/primary": "md.sys.color.primary",
      "Reflect Dark/primary": "md.sys.color.primary",
      "Reflect Light/on-primary": "md.sys.color.on-primary",
      "Reflect Dark/on-primary": "md.sys.color.on-primary",
      "Reflect Light/primary-container": "md.sys.color.primary-container",
      "Reflect Dark/primary-container": "md.sys.color.primary-container",
      "Reflect Light/on-primary-container": "md.sys.color.on-primary-container",
      "Reflect Dark/on-primary-container": "md.sys.color.on-primary-container",
      "Reflect Light/secondary-container": "md.sys.color.secondary-container",
      "Reflect Dark/secondary-container": "md.sys.color.secondary-container",
      "Reflect Light/on-secondary-container": "md.sys.color.on-secondary-container",
      "Reflect Dark/on-secondary-container": "md.sys.color.on-secondary-container",
      "Reflect Light/outline": "md.sys.color.outline",
      "Reflect Dark/outline": "md.sys.color.outline",
      "Reflect Light/error": "md.sys.color.error",
      "Reflect Dark/error": "md.sys.color.error"
    },
    "typography": {
      "symbols": {
        "Reflect/headline/large": "md.sys.typescale.headline-large",
        "Reflect/headline/medium": "md.sys.typescale.headline-medium",
        "Reflect/headline/small": "md.sys.typescale.headline-small",
        "Reflect/title/large": "md.sys.typescale.title-large",
        "Reflect/title/medium": "md.sys.typescale.title-medium",
        "Reflect/title/small": "md.sys.typescale.title-small",
        "Reflect/body/large": "md.sys.typescale.body-large",
        "Reflect/body/medium": "md.sys.typescale.body-medium",
        "Reflect/body/small": "md.sys.typescale.body-small",
        "Reflect/label/large": "md.sys.typescale.label-large",
        "Reflect/label/medium": "md.sys.typescale.label-medium",
        "Reflect/label/small": "md.sys.typescale.label-small"
      },
      "subproperties": {
        "fontFamily": "font",
        "fontWeight": "weight",
        "fontSize": "size",
        "letterSpacing": "tracking",
        "lineHeightPx": "line-height"
      }
    }
  },
  "compose": {
    "colors": {
      "md.sys.color.background": "MaterialTheme.colorScheme.background",
      "md.sys.color.error": "MaterialTheme.colorScheme.error",
      "md.sys.color.error-container": "MaterialTheme.colorScheme.errorContainer",
      "md.sys.color.inverse-on-surface": "MaterialTheme.colorScheme.inverseOnSurface",
      "md.sys.color.inverse-surface": "MaterialTheme.colorScheme.inverseSurface",
      "md.sys.color.on-background": "MaterialTheme.colorScheme.onBackground",
      "md.sys.color.on-error": "MaterialTheme.colorScheme.onError",
      "md.sys.color.on-error-container": "MaterialTheme.colorScheme.onErrorContainer",
      "md.sys.color.on-primary": "MaterialTheme.colorScheme.onPrimary",
      "md.sys.color.on-primary-container": "MaterialTheme.colorScheme.onPrimaryContainer",
      "md.sys.color.on-secondary": "MaterialTheme.colorScheme.onSecondary",
      "md.sys.color.on-secondary-container": "MaterialTheme.colorScheme.onSecondaryContainer",
      "md.sys.color.on-surface": "MaterialTheme.colorScheme.onSurface",
      "md.sys.color.on-surface-variant": "MaterialTheme.colorScheme.onSurfaceVariant",
      "md.sys.color.on-tertiary": "MaterialTheme.colorScheme.onTertiary",
      "md.sys.color.on-tertiary-container": "MaterialTheme.colorScheme.onTertiaryContainer",
      "md.sys.color.outline": "MaterialTheme.colorScheme.outline",
      "md.sys.color.primary": "MaterialTheme.colorScheme.primary",
      "md.sys.color.primary-container": "MaterialTheme.colorScheme.primaryContainer",
      "md.sys.color.secondary": "MaterialTheme.colorScheme.secondary",
      "md.sys.color.secondary-container": "MaterialTheme.colorScheme.secondaryContainer",
      "md.sys.color.surface": "MaterialTheme.colorScheme.surface",
      "md.sys.color.surface-variant": "MaterialTheme.colorScheme.surfaceVariant",
      "md.sys.color.tertiary": "MaterialTheme.colorScheme.tertiary",
      "md.sys.color.tertiary-container": "MaterialTheme.colorScheme.tertiaryContainer"
    },
    "typography": {
      "symbols": {
        "md.sys.typescale.display-large": "MaterialTheme.typography.displayLarge",
        "md.sys.typescale.display-medium": "MaterialTheme.typography.displayMedium",
        "md.sys.typescale.display-small": "MaterialTheme.typography.displaySmall",
        "md.sys.typescale.headline-large": "MaterialTheme.typography.headlineLarge",
        "md.sys.typescale.headline-medium": "MaterialTheme.typography.headlineMedium",
        "md.sys.typescale.headline-small": "MaterialTheme.typography.headlineSmall",
        "md.sys.typescale.title-large": "MaterialTheme.typography.titleLarge",
        "md.sys.typescale.title-medium": "MaterialTheme.typography.titleMedium",
        "md.sys.typescale.title-small": "MaterialTheme.typography.titleSmall",
        "md.sys.typescale.body-large": "MaterialTheme.typography.bodyLarge",
        "md.sys.typescale.body-medium": "MaterialTheme.typography.bodyMedium",
        "md.sys.typescale.body-small": "MaterialTheme.typography.bodySmall",
        "md.sys.typescale.label-large": "MaterialTheme.typography.labelLarge",
        "md.sys.typescale.label-medium": "MaterialTheme.typography.labelMedium",
        "md.sys.typescale.label-small": "MaterialTheme.typography.labelSmall"
      },
      "subproperties": {
        "font": "fontFamily",
        "weight": "fontWeight",
        "size": "fontSize",
        "tracking": "letterSpacing",
        "line-height": "lineHeight"
      }
    },
    "options": {
      "packages": {
        "MaterialTheme": "androidx.compose.material3"
      }
    }
  }
}

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

  1. בודקים את קובץ המיפוי, במיוחד את האופן שבו הוא ממפה מחדש את מאפייני הטיפוגרפיה מ-Figma לפורמט ש-Compose מצפה לו.

ייבוא מחדש של חבילות ממשק משתמש

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

כדי לייבא מחדש חבילות ממשק משתמש:

  1. ב-Android Studio, לוחצים על קובץ > חדש > ייבוא חבילות ממשק משתמש. תופיע תיבת הדו-שיח Import UI Packages.
  2. בתיבת הטקסט של כתובת ה-URL של המקור ב-Figma, מזינים את כתובת ה-URL של קובץ המקור ב-Figma.
  3. מסמנים את התיבה Translate Figma styles to Compose theme (תרגום הסגנונות מ-Figma לנושא של Compose).
  4. בוחרים באפשרות ייבוא הגדרה מותאמת אישית. לוחצים על סמל התיקייה ובוחרים את הקובץ שיצרתם: src/main/ui-package-resources/style-mappings/figma_styles.json.
  5. לוחצים על הבא. תוצג תצוגה מקדימה של חבילות ממשק המשתמש של הקובץ.
  6. לוחצים על יצירה. החבילות מיובאות לפרויקט.

תיבת הדו-שיח Import UI Packages

  1. יוצרים מחדש את הפרויקט ופותחים את הקובץ switch/Switch.kt כדי להציג את הקוד שנוצר.

Switch.kt (נוצר)

@Composable
fun ActiveOverlay(
    modifier: Modifier = Modifier,
    content: @Composable RelayContainerScope.() -> Unit
) {
    RelayContainer(
        backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
        isStructured = false,
        radius = 32.0,
        content = content,
        modifier = modifier.fillMaxWidth(1.0f).fillMaxHeight(1.0f)
    )
}
  1. שימו לב שהפרמטר backgroundColor מוגדר לשדה MaterialTheme.colorScheme.surfaceVariant באובייקט של נושא ה-Compose.
  2. מריצים את הפרויקט ומפעילים את המצב הכהה במהדמ. העיצוב הוחל בצורה נכונה והבאגים החזותיים תוקנו.

6cf2aa19fabee292.png

9. מזל טוב

מעולה! למדתם איך לשלב את Relay באפליקציות Compose.

מידע נוסף