القيود وترتيب مفاتيح التعديل

في Compose، يمكنك ربط عدة معدِّلات معًا لتغيير مظهر الدالة المركّبة وطريقة عملها. يمكن أن تؤثر سلاسل المُعدِّلات هذه في القيود التي يتم تمريرها إلى الدوال المركّبة، والتي تحدّد حدود العرض والارتفاع.

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

المعدِّلات في شجرة واجهة المستخدم

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

في شجرة واجهة المستخدم، يمكنك عرض المُعدِّلات كعُقد تضمين لعُقد التنسيق:

رمز للدوال المركّبة والمعدِّلات، وتمثيلها المرئي كشجرة واجهة مستخدم
الشكل 1. تعديلات على عُقد التنسيق في شجرة واجهة المستخدم

تؤدي إضافة أكثر من مفتاح تعديل واحد إلى دالة مركّبة إلى إنشاء سلسلة من مفاتيح التعديل. عند ربط عدة معدِّلات، يلتف كل عقدة معدِّل حول بقية السلسلة وعقدة التنسيق داخلها. على سبيل المثال، عند ربط معدِّل clip ومعدِّل size، تلتف عقدة المعدِّل clip حول عقدة المعدِّل size، والتي تلتف بعد ذلك حول عقدة التنسيق Image.

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

كما هو موضّح في الشكل 2، يتكوّن تنفيذ الدالتَين المركّبتَين Image وText من سلسلة من المُعدِّلات التي تلتف حول عقدة تنسيق واحدة.

إنّ عمليات تنفيذ Row وColumn هي عُقد تخطيط تصف كيفية تخطيط العناصر الثانوية.

بنية الشجرة السابقة، ولكن الآن كل عقدة هي مجرد تنسيق بسيط، مع الكثير من عقد التفاف المُعدِّل حولها.
الشكل 2. بنية الشجرة نفسها كما في الشكل 1، ولكن مع دوال مركّبة في شجرة واجهة المستخدم تظهر كسلاسل من المُعدِّلات

باختصار:

  • تلتف المعدِّلات حول معدِّل واحد أو عقدة تنسيق واحدة.
  • يمكن لعُقد التنسيق أن تنسّق عُقدًا فرعية متعددة.

توضّح الأقسام التالية كيفية استخدام هذا النموذج الذهني للتفكير في تسلسل المُعدِّلات وكيفية تأثيره في حجم الدوال المركّبة.

القيود في مرحلة التخطيط

تتبع مرحلة التنسيق خوارزمية من ثلاث خطوات للعثور على عرض كل عقدة تنسيق وارتفاعها وإحداثيات x وy:

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

تساعد Constraints في العثور على الأحجام المناسبة للعُقَد خلال الخطوتَين الأوليَين من الخوارزمية. تحدّد القيود الحدود الدنيا والقصوى لعرض العقدة وارتفاعها. عندما تحدّد العقدة حجمها، يجب أن يقع حجمها المقاس ضمن نطاق الحجم هذا.

أنواع القيود

يمكن أن يكون القيد واحدًا مما يلي:

  • محدودة: تحتوي العقدة على حد أقصى وحد أدنى للعرض والارتفاع.
قيود محدودة بأحجام مختلفة داخل حاوية
الشكل 3. القيود المقيّدة
  • غير محدودة: لا تتقيّد العقدة بأي حجم. يتم ضبط الحد الأقصى للعرض والارتفاع على ما لا نهاية.
القيود غير المحدودة التي تم ضبط العرض والارتفاع فيها على ما لا نهاية تمتد القيود إلى ما وراء الحاوية.
الشكل 4. قيود غير محدودة
  • Exact: يُطلب من العقدة اتّباع متطلبات حجم دقيقة. يتم ضبط الحدين الأدنى والأقصى على القيمة نفسها.
قيود دقيقة تتوافق مع متطلبات الحجم الدقيق داخل الحاوية.
الشكل 5: القيود الدقيقة:
  • مزيج: تتبع العقدة مزيجًا من أنواع القيود السابقة. على سبيل المثال، يمكن أن يحدّ القيد من العرض مع السماح بارتفاع أقصى غير محدود، أو يمكنه ضبط عرض دقيق مع توفير ارتفاع محدود.
حاويتان تعرضان مجموعات من القيود المحدودة وغير المحدودة والعرض والارتفاع الدقيقين.
الشكل 6: مجموعات من القيود المحدودة وغير المحدودة والعروض والارتفاعات الدقيقة.

يصف القسم التالي كيفية تمرير هذه القيود من عنصر رئيسي إلى عنصر فرعي.

كيفية تمرير القيود من العنصر الرئيسي إلى العنصر الثانوي

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

عندما تقيس عقدة رئيسية عقدها الفرعية، فإنها توفر هذه القيود لكل عقدة فرعية لإعلامها بالحجم المسموح به. بعد ذلك، عندما يقرر حجمه، فإنه يلتزم أيضًا بالقيود التي تم تمريرها من قبل والديه.

بشكل عام، تعمل الخوارزمية على النحو التالي:

  1. لتحديد الحجم الذي تريد العقدة الجذرية في شجرة واجهة المستخدم أن تشغله، تقيس العقدة الجذرية حجم العقد الفرعية وتعيد توجيه القيود نفسها إلى العقدة الفرعية الأولى.
  2. إذا كان العنصر الثانوي عبارة عن معدِّل لا يؤثر في القياس، تتم إعادة توجيه القيود إلى المعدِّل التالي. يتم تمرير القيود إلى سلسلة المُعدِّلات كما هي ما لم يتم الوصول إلى مُعدِّل يؤثر في القياس. بعد ذلك، تتم إعادة ضبط حجم القيود وفقًا لذلك.
  3. Once a node is reached that doesn't have any children (referred to as a "leaf node"), it decides its size based on the constraints that were passed in, and returns this resolved size to its parent.
  4. يعدّل العنصر الرئيسي قيوده بناءً على قياسات هذا العنصر الفرعي، ويستدعي العنصر الفرعي التالي بهذه القيود المعدَّلة.
  5. بعد قياس جميع العناصر الفرعية للعنصر الرئيسي، يحدّد العنصر الرئيسي حجمه الخاص ويبلّغ العنصر الرئيسي الخاص به بذلك.
  6. بهذه الطريقة، يتم اجتياز الشجرة بأكملها بالعمق أولاً. في النهاية، تكون جميع العُقد قد حدّدت أحجامها، وتكتمل خطوة القياس.

للحصول على مثال مفصّل، يمكنك مشاهدة فيديو القيود وترتيب المُعدِّلات.

المعدِّلات التي تؤثر في القيود

لقد تعرّفت في القسم السابق على أنّ بعض المُعدِّلات يمكن أن تؤثر في حجم القيود. توضّح الأقسام التالية المعدِّلات المحدّدة التي تؤثر في القيود.

معدِّل size

يحدّد المُعدِّل size الحجم المفضّل للمحتوى.

على سبيل المثال، يجب عرض شجرة واجهة المستخدم التالية في حاوية بحجم 300dp في 200dp. القيود محدودة، وتسمح بعرض يتراوح بين 100dp و300dp، وارتفاع يتراوح بين 100dp و200dp:

جزء من شجرة واجهة المستخدم مع معدِّل الحجم الذي يلتف حول عقدة التنسيق، و
  تمثيل القيود المحدودة التي يضعها معدِّل الحجم في حاوية.
الشكل 7. القيود المحدودة في شجرة واجهة المستخدم وتمثيلها في حاوية

يُعدّل المُعدِّل size القيود الواردة لتتطابق مع القيمة التي تم تمريرها إليه. في هذا المثال، القيمة هي 150dp:

الصورة نفسها في الشكل 7، باستثناء معدِّل الحجم الذي يكيّف القيود الواردة لتتطابق مع القيمة التي تم تمريرها إليه.
الشكل 8 يعدّل المعدِّل size القيود إلى 150dp.

إذا كان العرض والارتفاع أصغر من أصغر حدّ للقيود، أو أكبر من أكبر حدّ للقيود، يطابق المُعدِّل القيود التي تم تمريرها بأكبر قدر ممكن مع الالتزام بالقيود التي تم تمريرها في:

شجرتا واجهة مستخدم وتمثيلهما المقابل في الحاويات. في الحالة الأولى، يقبل معدِّل الحجم القيود الواردة، وفي الحالة الثانية، يتكيّف معدِّل الحجم مع القيود الكبيرة جدًا قدر الإمكان، ما يؤدي إلى قيود تملأ الحاوية.
الشكل 9: المعدِّل size الذي يلتزم بالقيود التي تم تمريرها بأكبر قدر ممكن

يُرجى العِلم أنّه لا يمكن ربط عدة مُعدِّلات size معًا. يضبط المعدِّل الأول size كلاً من الحدّ الأدنى والحدّ الأقصى للقيود على قيمة ثابتة. حتى إذا طلب معدِّل الحجم الثاني حجمًا أصغر أو أكبر، سيظل عليه الالتزام بالحدود الدقيقة التي تم تمريرها، لذا لن يتجاوز هذه القيم:

سلسلة من معدِّلَي حجم في شجرة واجهة المستخدم وتمثيلها في حاوية،
  وهي نتيجة القيمة الأولى التي تم تمريرها وليس القيمة الثانية.
الشكل 10: سلسلة من معدِّلَين (size)، حيث لا تلغي القيمة الثانية التي تم تمريرها (50dp) القيمة الأولى (100dp).

معدِّل requiredSize

استخدِم المُعدِّل requiredSize بدلاً من size إذا أردت أن تتجاهل العقدة القيود الواردة. يحلّ المُعدِّل requiredSize محلّ القيود الواردة ويمرّر الحجم الذي تحدّده كحدود دقيقة.

عندما يتم تمرير الحجم مرة أخرى إلى أعلى الشجرة، سيتم توسيط العقدة الفرعية في المساحة المتاحة:

معدّلا size وrequiredSize في سلسلة في شجرة واجهة المستخدم، والتمثيل المقابل في حاوية تتجاوز قيود المُعدِّل requiredSize قيود المُعدِّل size.
الشكل 11: يتجاهل المُعدِّل requiredSize القيود الواردة من المُعدِّل size.

المعدّلان width وheight

يعدّل المُعدِّل size كلاً من عرض القيود وارتفاعها. باستخدام المُعدِّل width، يمكنك ضبط عرض ثابت ولكن ترك الارتفاع بدون تحديد. وبالمثل، باستخدام المُعدِّل height، يمكنك ضبط ارتفاع ثابت، ولكن يمكنك ترك العرض غير محدد:

شجرتا واجهة مستخدم، إحداهما تحتوي على معدِّل العرض وتمثيل الحاوية الخاص به والأخرى تحتوي على معدِّل الارتفاع وتمثيله.
الشكل 12: يضبط المعدِّل width والمعدِّل height عرضًا وارتفاعًا ثابتَين على التوالي.

معدِّل sizeIn

يتيح لك المُعدِّل sizeIn ضبط قيود دقيقة للحدّ الأدنى والأقصى للعرض والارتفاع. يمكنك استخدام المعدِّل sizeIn إذا كنت بحاجة إلى تحكّم دقيق في القيود.

شجرة واجهة مستخدم مع معدِّل sizeIn مع ضبط الحد الأدنى والحد الأقصى للعرض والارتفاع،
  وتمثيلها داخل حاوية.
الشكل 13: المعدِّل sizeIn مع ضبط minWidth وmaxWidth وminHeight وmaxHeight

أمثلة

يعرض هذا القسم ويشرح الناتج من عدة مقتطفات الرمز مع معدّلات متسلسلة.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

ينتج عن هذا المقتطف الناتج التالي:

مربّع أزرق يملأ الحاوية الرئيسية
الشكل 14. يملأ العنصر Image الحد الأقصى للحجم نتيجةً لسلسلة المُعدِّلات.
  • يغيّر المُعدِّل fillMaxSize القيود لضبط كل من الحد الأدنى للعرض والارتفاع على القيمة القصوى، أي 300dp للعرض و200dp للارتفاع.
  • على الرغم من أنّ المُعدِّل size يريد استخدام حجم 50dp، إلا أنّه لا يزال بحاجة إلى الالتزام بالحد الأدنى من القيود الواردة. لذلك، سيؤدي المُعدِّل size أيضًا إلى إخراج حدود القيود الدقيقة لـ 300 في 200، مع تجاهل القيمة المقدَّمة في المُعدِّل size بشكل فعّال.
  • يتبع Image هذه الحدود ويبلغ عن حجم 300 في 200، والذي يتم تمريره على طول الشجرة.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

ينتج عن هذا المقتطف الناتج التالي:

مربّع أزرق صغير في وسط الحاوية الرئيسية
الشكل 15: يتم توسيط Image وتغيير حجمه إلى 50dp.
  • يعدّل المُعدِّل fillMaxSize القيود لضبط الحدّ الأدنى للعرض والارتفاع على القيمة القصوى، أي 300dp للعرض و200dp للارتفاع.
  • يؤدي المُعدِّل wrapContentSize إلى إعادة ضبط الحد الأدنى للقيود. لذلك، في حين أنّ fillMaxSize أدّى إلى قيود ثابتة، فإنّ wrapContentSize يعيد ضبطه على قيود محدودة. يمكن للعقدة التالية الآن أن تشغل المساحة بأكملها مرة أخرى، أو أن تكون أصغر من المساحة بأكملها.
  • يضبط المُعدِّل size القيود على الحدّين الأدنى والأقصى لـ 50.
  • يتم تحديد حجم Image على أنّه 50 في 50، ويتم تطبيق ذلك من خلال المبدّل size.
  • يحتوي المُعدِّل wrapContentSize على سمة خاصة. ويأخذ العنصر الفرعي ويضعه في منتصف الحد الأدنى المتاح من الحدود التي تم تمريرها إليه. وبالتالي، يكون الحجم الذي يتم إرساله إلى العناصر الرئيسية مساويًا للحدود الدنيا التي تم تمريرها إليه.

من خلال الجمع بين ثلاثة معدِّلات فقط، يمكنك تحديد حجم الدالة المركّبة وتوسيطها في الدالة الرئيسية.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .clip(CircleShape)
        .padding(10.dp)
        .size(100.dp)
)

ينتج عن هذا المقتطف الناتج التالي:

شكل دائري تم اقتصاصه بشكل غير صحيح بسبب
       ترتيب المُعدِّل.
الشكل 16. شكل تم اقتصاصه بشكل غير صحيح بسبب ترتيب المُعدِّل
  • لا يغيّر المُعدِّل clip القيود.
  • يؤدي المُعدِّل padding إلى خفض الحدّ الأقصى للقيود.
  • يضبط المُعدِّل size جميع القيود على 100dp.
  • يلتزم Image بهذه القيود ويعرض حجمًا يبلغ 100dp في 100dp.
  • يضيف المُعدِّل padding مساحة 10dp على جميع الجوانب إلى الحجم الذي يعرضه Image، وبالتالي يعرض التنسيق الذي يتضمّن مساحة متروكة عرضًا وارتفاعًا بقيمة 120dp.
  • الآن، في مرحلة الرسم، يعمل المُعدِّل clip على لوحة رسم بحجم 120dp في 120dp. يؤدي ذلك إلى إنشاء قناع دائري بهذا الحجم.
  • بعد ذلك، يُدرج المُعدِّل padding محتواه بمقدار 10dp على جميع الجوانب، ما يؤدي إلى تقليل حجم لوحة الرسم لـ Image إلى 100dp في 100dp.
  • يتم رسم Image في تلك اللوحة الأصغر حجمًا. يتم اقتصاص الصورة استنادًا إلى الدائرة الأصلية لـ 120dp، وبالتالي تكون النتيجة غير دائرية.