إنشاء أساسيات التصميم

تسهّل Jetpack Compose عملية تصميم واجهة المستخدم لتطبيقك وإنشائها. تحوّل Compose الحالة إلى عناصر واجهة المستخدم من خلال:

  1. تركيب العناصر
  2. تخطيط العناصر
  3. رسم العناصر

تحويل حالة Compose إلى واجهة مستخدم من خلال التركيب والتصميم والرسم

يركّز هذا المستند على تخطيط العناصر، ويشرح بعض اللبنات الأساسية التي يوفّرها Compose لمساعدتك في تخطيط عناصر واجهة المستخدم.

أهداف التنسيقات في Compose

يستند تنفيذ نظام التصميم في Jetpack Compose إلى هدفَين رئيسيَّين:

أساسيات الدوال القابلة للإنشاء

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

قد تُصدر دالة مركّبة عدة عناصر في واجهة المستخدم. ومع ذلك، إذا لم تقدّم إرشادات حول كيفية ترتيبها، قد ترتّب Compose العناصر بطريقة لا تعجبك. على سبيل المثال، ينشئ هذا الرمز عنصرَين نصيَّين:

@Composable
fun ArtistCard() {
    Text("Alfred Sisley")
    Text("3 minutes ago")
}

بدون إرشادات حول كيفية ترتيبها، يكدّس Compose عناصر النص فوق بعضها البعض، ما يجعلها غير قابلة للقراءة:

عنصران نصيان مرسومَين فوق بعضهما البعض، ما يجعل النص غير قابل للقراءة

توفّر Compose مجموعة من التصاميم الجاهزة للاستخدام لمساعدتك في ترتيب عناصر واجهة المستخدم، كما تسهّل عليك تحديد تصاميمك الخاصة الأكثر تخصصًا.

مكوّنات التنسيق العادي

في كثير من الحالات، يمكنك استخدام عناصر التنسيق العادي في Compose.

استخدِم Column لوضع العناصر عموديًا على الشاشة.

@Composable
fun ArtistCardColumn() {
    Column {
        Text("Alfred Sisley")
        Text("3 minutes ago")
    }
}

عنصران نصيان مرتّبان في تخطيط عمودي، ما يتيح قراءة النص

وبالمثل، استخدِم Row لوضع العناصر أفقيًا على الشاشة. يتيح كل من Column وRow ضبط محاذاة العناصر التي يحتويان عليها.

@Composable
fun ArtistCardRow(artist: Artist) {
    Row(verticalAlignment = Alignment.CenterVertically) {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Column {
            Text(artist.name)
            Text(artist.lastSeenOnline)
        }
    }
}

تعرض تخطيطًا أكثر تعقيدًا، مع رسم صغير بجانب عمود من عناصر النص

استخدِم Box لوضع عناصر فوق بعضها البعض. يتيح Box أيضًا ضبط محاذاة محدّدة للعناصر التي يتضمّنها.

@Composable
fun ArtistAvatar(artist: Artist) {
    Box {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Icon(Icons.Filled.Check, contentDescription = "Check mark")
    }
}

تعرض هذه السمة عنصرَين مكدّسَين فوق بعضهما البعض

في كثير من الأحيان، تكون هذه اللبنات الأساسية هي كل ما تحتاج إليه. يمكنك كتابة دالة مركّبة خاصة بك لدمج هذه التصاميم في تصميم أكثر تفصيلاً يناسب تطبيقك.

مقارنة بين ثلاثة عناصر بسيطة قابلة للإنشاء في التنسيق: العمود والصف والمربّع

لضبط موضع العناصر التابعة ضمن Row، اضبط وسيطتَي horizontalArrangement وverticalAlignment. بالنسبة إلى Column، اضبط وسيطتَي verticalArrangement وhorizontalAlignment:

@Composable
fun ArtistCardArrangement(artist: Artist) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.End
    ) {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Column { /*...*/ }
    }
}

العناصر محاذية إلى اليمين

نموذج التنسيق

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

باختصار، يتم قياس الوالدَين قبل الأطفال، ولكن يتم تحديد حجمهما وموضعهما بعد الأطفال.

ضَع في اعتبارك الدالة SearchResult التالية.

@Composable
fun SearchResult() {
    Row {
        Image(
            // ...
        )
        Column {
            Text(
                // ...
            )
            Text(
                // ...
            )
        }
    }
}

تنتج هذه الدالة شجرة واجهة المستخدم التالية.

SearchResult
  Row
    Image
    Column
      Text
      Text

في المثال SearchResult، يتبع تخطيط شجرة واجهة المستخدم الترتيب التالي:

  1. يُطلب من العقدة الجذر Row إجراء القياس.
  2. تطلب العقدة الجذر Row من العقدة الثانوية الأولى Image قياس حجمها.
  3. Image هي عقدة طرفية (أي ليس لديها عناصر فرعية)، لذا تعرض حجمًا وتعرض تعليمات موضع الإعلان.
  4. تطلب العقدة الجذر Row من العقدة الثانوية الثانية Column قياسها.
  5. تطلب العقدة Column من العقدة الثانوية الأولى Text قياس حجمها.
  6. عقدة Text الأولى هي عقدة فرعية، لذا تعرض حجمًا وتعرض تعليمات موضع الإعلان.
  7. تطلب العُقدة Column من العُقدة الثانوية الثانية Text إجراء القياس.
  8. العقدة الثانية Text هي عقدة طرفية، لذا تعرض حجمًا وتعرض تعليمات تحديد الموضع.
  9. بعد أن تقيس العقدة Column حجم العناصر التابعة لها وتضعها في مواضعها، يمكنها تحديد حجمها وموضعها.
  10. بعد أن تقيس العقدة الجذر Row حجم العناصر التابعة لها وتضعها في مكانها، يمكنها تحديد حجمها وموضعها.

ترتيب القياسات والأحجام والمواضع في شجرة واجهة مستخدم نتائج البحث

الأداء

تحقّق Compose أداءً عاليًا من خلال قياس الأطفال مرة واحدة فقط. يُعدّ القياس الذي يتم في مرحلة واحدة مناسبًا لتحسين الأداء، ما يتيح لـ Compose التعامل بكفاءة مع بنى واجهة المستخدم المعقّدة. إذا قاس أحد العناصر حجم العنصر التابع له مرتين، وقاس العنصر التابع حجم كل من العناصر التابعة له مرتين، وهكذا، فإنّ محاولة واحدة لتصميم واجهة مستخدم كاملة ستتطلّب الكثير من العمل، ما يصعّب الحفاظ على أداء تطبيقك.

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

بما أنّ القياس وموضع العناصر هما مرحلتان فرعيتان منفصلتان من عملية تحديد موضع العناصر، يمكن تنفيذ أي تغييرات تؤثر فقط في موضع العناصر، وليس في القياس، بشكل منفصل.

استخدام أدوات التعديل في تخطيطاتك

كما هو موضّح في معدِّلات الإنشاء، يمكنك استخدام المعدِّلات لتزيين العناصر القابلة للإنشاء أو تحسينها. تُعدّ المعدّلات ضرورية لتخصيص التنسيق. على سبيل المثال، نربط هنا عدة معدِّلات لتخصيص ArtistCard:

@Composable
fun ArtistCardModifiers(
    artist: Artist,
    onClick: () -> Unit
) {
    val padding = 16.dp
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(padding)
            .fillMaxWidth()
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ }
        Spacer(Modifier.size(padding))
        Card(
            elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
        ) { /*...*/ }
    }
}

تخطيط أكثر تعقيدًا، باستخدام أدوات تعديل لتغيير طريقة ترتيب الرسومات والمناطق التي تستجيب لبيانات أدخلها المستخدم

في الرمز البرمجي أعلاه، لاحظ دوال المعدِّل المختلفة المستخدَمة معًا.

  • تتفاعل الدالة البرمجية القابلة للإنشاء clickable مع إدخال المستخدم وتعرض تأثيرًا متتاليًا.
  • تضيف السمة padding مساحة حول أحد العناصر.
  • تجعل السمة fillMaxWidth الدالة المركّبة تملأ الحد الأقصى للعرض الذي يوفّره العنصر الرئيسي.
  • تحدّد size() العرض والارتفاع المفضّلين للعنصر.

التنسيقات القابلة للتمرير

يمكنك الاطّلاع على مزيد من المعلومات حول التصميمات القابلة للتمرير في مستند إيماءات Compose.

للاطّلاع على القوائم والقوائم الكسولة، يمكنك الرجوع إلى مستندات قوائم Compose.

التنسيقات المتجاوبة

يجب تصميم التخطيط مع مراعاة اتجاهات الشاشة المختلفة وأحجام الأجهزة. توفّر Compose بعض الآليات الجاهزة لتسهيل تكييف التنسيقات القابلة للإنشاء مع إعدادات الشاشة المختلفة.

القيود

لمعرفة القيود الواردة من العنصر الرئيسي وتصميم التخطيط وفقًا لذلك، يمكنك استخدام BoxWithConstraints. يمكن العثور على قيود القياس في نطاق دالة lambda الخاصة بالمحتوى. يمكنك استخدام قيود القياس هذه لإنشاء تخطيطات مختلفة لإعدادات الشاشة المختلفة:

@Composable
fun WithConstraintsComposable() {
    BoxWithConstraints {
        Text("My minHeight is $minHeight while my maxWidth is $maxWidth")
    }
}

التنسيقات المستندة إلى مواضع الإعلانات

توفّر Compose مجموعة كبيرة ومتنوّعة من الدوال المركّبة استنادًا إلى التصميم المتعدد الأبعاد مع androidx.compose.material:material الاعتمادية (المضمّنة عند إنشاء مشروع Compose في "استوديو Android") لتسهيل إنشاء واجهة المستخدم. يتم توفير عناصر مثل Drawer وFloatingActionButton وTopAppBar.

تستفيد مكونات Material بشكل كبير من واجهات برمجة التطبيقات الخاصة بفتحات التعبئة، وهو نمط تقدّمه Compose لإضافة طبقة من التخصيص فوق العناصر القابلة للإنشاء. يؤدي هذا الأسلوب إلى جعل المكوّنات أكثر مرونة، لأنّها تقبل عنصرًا ثانويًا يمكنه ضبط نفسه بدلاً من الاضطرار إلى عرض كل مَعلمة إعداد للعنصر الثانوي. تترك مواضع الإعلانات مساحة فارغة في واجهة المستخدم ليملأها المطوّر كما يشاء. على سبيل المثال، إليك المواضع التي يمكنك تخصيصها في TopAppBar:

مخطّط بياني يعرض الخانات المتاحة في شريط تطبيق "مكوّنات Material"

تستخدِم الدوال البرمجية القابلة للإنشاء عادةً تعبير lambda الخاص بالدالة البرمجية القابلة للإنشاء content ( content: @Composable () -> Unit). تعرض واجهات برمجة التطبيقات الخاصة بفتحات الإعلانات مَعلمات content متعددة لاستخدامات محدّدة. على سبيل المثال، تتيح لك السمة TopAppBar تقديم المحتوى الخاص بالسمات title وnavigationIcon وactions.

على سبيل المثال، تتيح لك Scaffold تنفيذ واجهة مستخدم باستخدام بنية التصميم الأساسية في التصميم المتعدد الأبعاد. توفّر Scaffold مساحات لأكثر مكونات التصميم المتعدد الأبعاد شيوعًا على المستوى الأعلى، مثل TopAppBar وBottomAppBar وFloatingActionButton وDrawer. باستخدام Scaffold، يمكنك التأكّد بسهولة من أنّ هذه المكوّنات موضوعة في المكان المناسب وتعمل معًا بشكلٍ صحيح.

تطبيق JetNews التجريبي الذي يستخدم Scaffold لتحديد موضع عناصر متعددة

@Composable
fun HomeScreen(/*...*/) {
    ModalNavigationDrawer(drawerContent = { /* ... */ }) {
        Scaffold(
            topBar = { /*...*/ }
        ) { contentPadding ->
            // ...
        }
    }
}