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

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

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

إنشاء حالة تحويل إلى واجهة المستخدم من خلال الإنشاء والتصميم والرسم

يركّز هذا المستند على تخطيط العناصر، ويوضّح بعض اللبنات الأساسية التي يوفّرها 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.

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

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

كما هو موضّح في عناصر تعديل 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 مجموعة كبيرة من العناصر القابلة للإنشاء استنادًا إلى Material Design مع التبعية androidx.compose.material:material (المضمّنة عند إنشاء مشروع Compose في "استوديو Android") لتسهيل عملية إنشاء واجهة المستخدم. يتم توفير عناصر مثل Drawer وFloatingActionButton وTopAppBar.

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

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

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

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

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

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