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

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

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

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

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

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

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

أساسيات الدوالّ المركّبة

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

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

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

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

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

يوفّر تطبيق 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.

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

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

كما هو موضّح في مقالة عناصر تعديل الإنشاء، يمكنك استخدام عناصر التعديل لتزيين العناصر القابلة للإنشاء أو تحسينها. إنّ عوامل التعديل ضرورية لتخصيص التنسيق. على سبيل المثال، نربط هنا عدة عوامل تعديل لتخصيص 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 تلقائيًا بعض الآليات ل تسهيل تكييف التنسيقات القابلة للتجميع مع إعدادات الشاشات المختلفة.

القيود

لمعرفة القيود الواردة من العنصر الرئيسي وتصميم التنسيق وفقًا لذلك، يمكنك استخدام BoxWithConstraints. يمكن العثور على قيود measuring في نطاق دالة 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 Components

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

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

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

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