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

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

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

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

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

  • ניסיון בסיסי עם 'כתיבה'. אם עדיין לא עשיתם זאת, אתם צריכים להשלים את קוד ה-Codelab של Jetpack פיתוח נייטיב.
  • ניסיון בתחביר Kotlin.

מה תלמדו

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

מה תפַתחו

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

האפליקציה הסופית

מה צריך להכין

2. להגדרה

לקבלת הקוד

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

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

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

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

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

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

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

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

חיבור Android Studio ל-Figma

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

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

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

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

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

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

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

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

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

מסך הבית

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

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

מעיינים במסך ההוספה/העריכה.

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

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

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

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

בדיקת העיצוב

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

סגנונות Figma

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

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

כדי לקבל את הקישור למקור של Figma, פועלים לפי השלבים הבאים:

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

88afd168463bf7e5.png

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

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

f75d0c3e17b6f75.png

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

התיקייה ui-packages

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

a6105146c4cfb47.png

פיתוח ויצירה של קוד

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

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, מפעילים את הפונקציה Composable Switch() כשהסוג הוא 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. הוספת מצב ואינטראקציה

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

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

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

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

  1. ב-Android Studio, פותחים את הקובץ java/com/google/relay/example/reflect/ui/components/SwitchControl.kt.
  2. בפונקציה SwitchControl() Composable, מעבירים את הפרמטרים הבאים:
  • trackerData: אובייקט TrackerData
  • modifier: אובייקט לעיצוב
  • onLongClick: קריאה חוזרת לאינטראקציה חוזרת שמאפשרת ללחוץ לחיצה ארוכה על מכשירי מעקב לעריכה ולמחיקה
  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. מיפוי רכיבים קיימים

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

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

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

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

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

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

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

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

רכיב Figma לשדה טקסט עם פלאגין של שרת ממסר בשכבת-על

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

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

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

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

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

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

e776585c3b838b10.png

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

text_field.json

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

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

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

TrackerSettings.kt (נוצר)

@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. מיפוי לעיצובים

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

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

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

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

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

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

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

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

תיבת הדו-שיח 'ייבוא חבילות של ממשק המשתמש'

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

6cf2aa19fabee292.png

9. מזל טוב

מעולה! למדת איך לשלב את שרת הממסר באפליקציות של הכתיבה!

מידע נוסף