إنشاء تطبيق كامل باستخدام Relay وJetpack Compose

1. قبل البدء

Relay هي مجموعة أدوات تتيح للفرق تصميم مكونات واجهة المستخدم في Figma واستخدامها مباشرةً في مشاريع Jetpack Compose. ويزيل هذا الإجراء الحاجة إلى مواصفات التصميم المملة ودورات تأكيد الجودة، ما يساعد الفِرق على تقديم واجهات مستخدم رائعة لنظام التشغيل Android بسرعة.

في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية دمج حِزم واجهة مستخدم Relay في عملية تطوير Compose. ويركز على أساليب الدمج، وليس سير العمل من البداية إلى النهاية. للتعرّف على سير العمل العام في تطبيق Relay، يُرجى الاطّلاع على الدليل التعليمي الأساسي لتطبيق Relay.

المتطلبات الأساسية

  • تجربة أساسية مع ميزة "إنشاء" إذا لم يسبق لك ذلك، أكمِل أساسيات Jetpack Compose في ورشة رموز المصدر.
  • خبرة في بنية Kotlin

ما ستتعرّف عليه

  • كيفية استيراد حِزم واجهة المستخدم
  • كيفية دمج حِزم واجهة المستخدم مع بنية البيانات والتنقّل
  • كيفية لف حزم واجهة المستخدم باستخدام منطق وحدة التحكّم
  • كيفية ربط أنماط Figma بمظهر Compose
  • كيفية استبدال حِزم واجهة المستخدم بعناصر قابلة للتجميع حالية في الرمز الذي تم إنشاؤه

التطبيق الذي ستصممه

  • تصميم تطبيق واقعي يستند إلى حِزم Relay التي يقدّمها مصمّم يُطلق على التطبيق اسم Reflect، وهو تطبيق تتبُّع يومي يشجع على التأمل والاعتياد على العادات الجيدة. يحتوي على مجموعة من أجهزة التتبُّع بأنواع مختلفة وواجهة مستخدم لإضافتها وإدارتها. يظهر التطبيق على النحو الموضّح في الصورة التالية:

التطبيق المكتمل

المتطلبات

2. الإعداد

الحصول على الرمز

للحصول على رمز هذا الدليل التعليمي حول الرموز البرمجية، يمكنك اتّباع أحد الإجراءَين التاليَين:

$ git clone https://github.com/googlecodelabs/relay-codelabs
  • انتقِل إلى مستودع relay-codelabs على GitHub، واختَر الفرع المطلوب، ثم انقر على الرمز > تنزيل ملف zip وفك ضغط ملف zip الذي تم تنزيله.

في كلتا الحالتَين، يحتوي الفرع main على الرمز المبدئي ويحتوي الفرع end على رمز الحلّ.

تثبيت المكوّن الإضافي Relay for Android Studio

إذا لم يكن لديك المكوّن الإضافي Relay for Android Studio، اتّبِع الخطوات التالية:

  1. في Android Studio، انقر على الإعدادات > المكونات الإضافية.
  2. في مربّع النص، أدخِل Relay for Android Studio.
  3. في الإضافة التي تظهر في نتائج البحث، انقر على تثبيت.

إعدادات المكوّن الإضافي في "استوديو Android"

  1. إذا ظهر لك مربّع حوار ملاحظة الخصوصية بشأن الإضافات التابعة لجهات خارجية، انقر على قبول.
  2. انقر على حسنًا > إعادة التشغيل.
  3. إذا ظهر لك مربّع حوار تأكيد الخروج، انقر على خروج.

ربط "استوديو Android" بتطبيق Figma

يسترجع Relay حِزم واجهة المستخدم باستخدام واجهة برمجة التطبيقات Figma API. لاستخدامه، تحتاج إلى حساب مجاني على Figma ورمز أمان وصول شخصي، لذلك تم إدراجهما في قسم المتطلّبات.

إذا لم يسبق لك ربط Android Studio بتطبيق Figma، اتّبِع الخطوات التالية:

  1. في حسابك على Figma، انقر على رمز ملفك الشخصي في أعلى الصفحة واختَر الإعدادات.
  2. في قسم رموز الوصول الشخصية، أدخِل وصفًا للرمز المميّز في مربّع النص، ثم اضغط على Enter (أو return على نظام التشغيل macOS). يتم إنشاء رمز مميّز.
  3. انقر على نسخ هذا الرمز المميّز.

رمز دخول تم إنشاؤه في Figma

  1. في Android Studio، اختَر الأدوات > إعدادات الإعادة. يظهر مربّع حوار إعدادات التوسّط.
  2. في مربّع نص رمز دخول Figma، الصِق رمز الدخول ثم انقر على حسنًا. تم إعداد بيئتك.

3- مراجعة تصميم التطبيق

بالنسبة إلى تطبيق Reflect، تعاونّا مع مصمّم لمساعدتنا في تحديد لون التطبيق وأسلوب الخط وتنسيقه وسلوكه. لقد أنشأنا هذه التصاميم وفقًا لمعيار Material Design 3 لكي يعمل التطبيق بسلاسة مع مكوّنات وألوان Material Design.

مراجعة الشاشة الرئيسية

تعرض الشاشة الرئيسية قائمة بالمتتبّعين المحدّدين من قِبل المستخدم. وتوفّر أيضًا إمكانات لتغيير اليوم النشط وإنشاء أجهزة تتبُّع أخرى.

الشاشة الرئيسية

في Figma، قسم المصمّم هذه الشاشة إلى مكونات متعددة وحدّد واجهات برمجة التطبيقات الخاصة بها وحزّمها باستخدام مكوّن Relay الإضافي في Figma. بعد تجميع هذه المكوّنات، يمكنك استيرادها إلى مشروعك على Android Studio.

مكوّن الشاشة الرئيسية

راجِع شاشة الإضافة/التعديل.

تتيح شاشة الإضافة/التعديل للمستخدمين إضافة أجهزة التتبُّع أو تعديلها. يختلف النموذج المعروض قليلاً استنادًا إلى نوع التتبُّع.

شاشة الإضافة/التعديل

وبالمثل، يتم تقسيم هذه الشاشة إلى مكونات مُجمَّعة متعددة.

إضافة/تعديل مكوّنات الشاشة

مراجعة المظهر

تم تنفيذ ألوان هذا التصميم وأسلوب الخط فيه على أنّهما أسلوبان في Figma استنادًا إلى أسماء الرموز في التصميم المتعدد الأبعاد 3. ويؤدي ذلك إلى تحسين إمكانية التشغيل التفاعلي مع مظاهر Compose ومكونات Material.

أنماط Figma

4. استيراد حِزم واجهة المستخدم

قبل أن تتمكّن من استيراد حِزم واجهة المستخدم إلى مشروعك، عليك تحميل مصدر التصميم إلى Figma.

للحصول على رابط إلى مصدر Figma، اتّبِع الخطوات التالية:

  1. في Figma، انقر على استيراد ملف، ثم اختَر ملف ReflectDesign.fig المتوفّر في مجلد المشروع CompleteAppCodelab.
  2. انقر بزر الماوس الأيمن على الملف، ثم اختَر نسخ الرابط. ستحتاج إليه في القسم التالي.

88afd168463bf7e5.png

استيراد حِزم واجهة المستخدم إلى المشروع

  1. في "استوديو Android"، افتح مشروع ./CompleteAppCodelab.
  2. انقر على ملف > جديد > استيراد حِزم واجهة المستخدم. يظهر مربّع حوار استيراد حِزم واجهة المستخدم.
  3. في مربّع نص عنوان URL لمصدر Figma، الصِق عنوان 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. تعرض وحدة Relay معاينة للحزمة وواجهة برمجة التطبيقات الخاصة بها.

a6105146c4cfb47.png

إنشاء الرمز البرمجي وإنشاؤه

  1. في أعلى "استوديو Android"، انقر على b3bc77f3c78cac1b.png إنشاء مشروع. تتم إضافة الرمز الذي تم إنشاؤه لكل حزمة إلى مجلد java/com.google.relay.example.reflect. تحتوي العناصر القابلة للتجميع التي تم إنشاؤها على جميع معلومات التنسيق والتصميم من تصميم Figma.
  2. افتح ملف com/google/relay/example/reflect/range/Range.kt.
  3. يُرجى العلم أنّه يتم إنشاء معاينات ميزة "الإنشاء" لكلّ صيغة مكوّن. إذا لزم الأمر، انقر على تقسيم حتى يظهر لك رمز المحتوى ولوحة المعاينة بجانب بعضهما.

c0d21ab0622ad550.png

5- دمج المكوّنات

في هذا القسم، يمكنك إلقاء نظرة عن كثب على الرمز الذي تم إنشاؤه لتتبُّع Switch.

تصميم أداة تتبُّع التبديل

  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. أعِد إنشاء المشروع. تعرض الصفحة الرئيسية الآن أداة تتبُّع التبديل بشكلٍ صحيح كما هو مصمّم باستخدام البيانات المباشرة.

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: دالة استدعاء للتفاعل لتفعيل الضغط مع الاستمرار على أجهزة التتبُّع من أجل التعديل والحذف
  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"، أنشئ التطبيق وشغِّله في المحاكي.
  2. اضغط مع الاستمرار على صفّ جهاز التتبُّع واختَر تعديل.
  3. انقر على حقل النص Title وتلاحظ أنّه لا يستجيب للتفاعل.

لاستبدال التنفيذ الفعلي لهذا العنصر، تحتاج إلى شيئَين: حزمة واجهة مستخدم حقل نص وملف ربط. لحسن الحظ، سبق أن حزّم مصمّمنا مكونات نظام التصميم في Figma واستخدَم مكوّن حقل نصّ في تصميمه لتطبيق Tracker Settings. يتم إنشاء هذه الحزمة المُدمجة تلقائيًا كتبعية، ولكن يمكنك استخدام ربط المكوّنات لتبديلها.

مكوّن Figma لحقل نصي مع مكوّن إضافي Relay متراكب

إنشاء ملف ربط

يقدّم المكوّن الإضافي Relay for Android Studio اختصارًا لإنشاء ملفات ربط المكوّنات.

لإنشاء ملف ربط، اتّبِع الخطوات التالية:

  1. في Android Studio، انقر بزر الماوس الأيمن على حزمة text_field واجهة المستخدم، ثم اختَر إنشاء ملف ربط.

إنشاء عنصر قائمة السياقات لملف الربط

  1. سيظهر مربّع حوار لملف الربط. أدخِل الخيارات التالية:
  • في العنصر المستهدف المكوّن، اختَر استخدام عنصر مكوّن حالي وأدخِل com.google.relay.example.reflect.ui.components.ReflectTextField.
  • في الملف الذي تم إنشاؤه، ضَع علامة في المربّع بجانب إنشاء عملية التنفيذ وأزِل العلامة من المربّع بجانب إنشاء معاينة Compose.

e776585c3b838b10.png

  1. انقر على إنشاء ملف الربط. سيؤدي ذلك إلى إنشاء ملف الربط التالي:

text_field.json

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

تحدِّد ملفات تعيين المكوّنات حزمة وهدف فئة Compose، بالإضافة إلى مجموعة اختيارية من كائنات fieldMapping. تتيح لك عمليات ربط الحقول هذه تحويل مَعلمات الحِزم إلى مَعلمات Compose المتوقّعة. في هذه الحالة، تكون واجهات برمجة التطبيقات متطابقة، لذا ما عليك سوى تحديد الفئة المستهدَفة.

  1. أعِد إنشاء المشروع.
  2. في ملف trackersettings/ TrackerSettings.kt، ابحث عن دالة TitleFieldStyleFilledStateEnabledTextConfigurationsInputText() Composable التي تم إنشاؤها وتلاحظ أنّها تتضمّن مكوّن 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. الربط بمظاهر Compose

ينشئ Relay تلقائيًا قيمًا حرفية للألوان وأسلوب الخط. يضمن ذلك دقة الترجمة، ولكنه يمنع المكونات من استخدام نظام تخصيص المظهر في تطبيق "الكتابة". يظهر ذلك بوضوح عند عرض تطبيقك في الوضع الداكن:

معاينة للشاشة الرئيسية باستخدام الوضع الداكن وعرض ألوان غير صحيحة

مكوّن التنقّل اليومي غير مرئي تقريبًا والألوان غير صحيحة. لحلّ هذه المشكلة، يمكنك استخدام ميزة ربط الأنماط في Relay لربط أنماط Figma بعناصر Compose theme tokens في الرمز الذي تم إنشاؤه. ويؤدي ذلك إلى زيادة الاتساق المرئي بين تطبيق Relay ومكونات Material Design 3، كما يتيح تفعيل الوضع الداكن.

1fac916db14929bb.png

إنشاء ملف ربط الأنماط

  1. في "استوديو Android"، انتقِل إلى الدليل 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، انقر على ملف > جديد > استيراد حِزم واجهة المستخدم. يظهر مربّع حوار استيراد حِزم واجهة المستخدم.
  2. في مربّع نص عنوان URL لمصدر Figma، أدخِل عنوان URL لملف المصدر في Figma.
  3. ضَع علامة في مربّع الاختيار ترجمة أنماط Figma إلى مظهر Compose.
  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 في كائن موضوع Compose.
  2. شغِّل المشروع وفعِّل الوضع الداكن في المحاكي. تم تطبيق المظهر بشكل صحيح وتم إصلاح الأخطاء المرئية.

6cf2aa19fabee292.png

9. تهانينا

تهانينا! لقد تعرّفت على كيفية دمج Relay في تطبيقات Compose.

مزيد من المعلومات