تتيح لك المُعدِّلات تزيين عنصر قابل للتجميع أو تحسينه. تتيح لك المُعدِّلات تنفيذ الإجراءات التالية:
- تغيير حجم العنصر القابل للتجميع وتنسيقه وسلوكه ومظهره
- إضافة معلومات، مثل تصنيفات تسهيل الاستخدام
- معالجة بيانات المستخدم
- إضافة تفاعلات عالية المستوى، مثل جعل عنصر قابلاً للنقر أو التمرير أو السحب أو التكبير/التصغير
المُعدِّلات هي عناصر Kotlin عادية. أنشئ مُعدِّلًا من خلال استدعاء إحدى دوالّ فئة
Modifier
:
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
يمكنك ربط هذه الدوال معًا لإنشاءها:
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
في الرمز البرمجي أعلاه، لاحظ الدوالّ المعدِّلة المختلفة المستخدَمة معًا.
- تُستخدَم العلامة
padding
لوضع مساحة حول عنصر. - تؤدي القيمة
fillMaxWidth
إلى ملء العنصر القابل للتجميع الحد الأقصى للعرض الذي تم منحه له من عنصره الرئيسي.
من أفضل الممارسات أن تقبل جميع العناصر القابلة للتجميع مَعلمة modifier
، وأن تُمرِّر هذا المُعدِّل إلى العنصر الثانوي الأول الذي يُنشئ واجهة المستخدم.
يؤدي ذلك إلى جعل
الرمز البرمجي أكثر قابلية لإعادة الاستخدام، كما يجعل سلوكه أكثر قابلية للتوقّع وسهولة. للحصول على
مزيد من المعلومات، يُرجى الاطّلاع على إرشادات Compose API، Elements accept and respect a
Modifier parameter.
ترتيب المُعدِّلات مهمّ
إنّ ترتيب دوالّ المُعدِّلات مهم. بما أنّ كل دالة تُجري
تغييرات على Modifier
الذي تعرضه الدالة السابقة، يؤثر التسلسل
في النتيجة النهائية. لنطّلِع على مثال على ذلك:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
في الرمز البرمجي أعلاه، يمكن النقر على المنطقة بأكملها، بما في ذلك
المسافة المحيطة، لأنّه تم تطبيق المُعدِّل padding
بعد المُعدِّل clickable
. في حال عكس ترتيب عوامل التعديل، لن تستجيب المساحة التي تمت إضافتها باستخدام padding
لإدخال المستخدم:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
مفاتيح التعديل المضمّنة
يوفّر Jetpack Compose قائمة بعوامل التعديل المدمجة لمساعدتك في تزيين عنصر قابل للتركيب أو تعزيزه. في ما يلي بعض المُعدِّلات الشائعة التي ستستخدمها لتعديل التنسيقات.
padding
وsize
يتم تلقائيًا إلحاق العناصر الفرعية بالتنسيقات المقدَّمة في ميزة "الإنشاء". ومع ذلك،
يمكنك ضبط حجم باستخدام المُعدِّل size
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
يُرجى العِلم أنّه قد لا يتم الالتزام بالحجم الذي حدّدته إذا لم يكن يستوفي
القيود الواردة من العنصر الرئيسي للتنسيق. إذا كنت بحاجة إلى تثبيت
حجم العنصر القابل للتجميع بغض النظر عن القيود الواردة، استخدِم المُعدِّل requiredSize
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
في هذا المثال، حتى مع ضبط العنصر الرئيسي height
على 100.dp
، سيكون ارتفاع
Image
هو 150.dp
، لأنّ معدِّل requiredSize
يأخذ
الأولوية.
إذا كنت تريد أن يملؤه تنسيق فرعي كل الارتفاع المتاح الذي يسمح به التنسيق
الرئيسي، أضِف المُعدِّل fillMaxHeight
(تتيح ميزة "الإنشاء" أيضًا استخدام
fillMaxSize
وfillMaxWidth
):
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
لإضافة مسافة بادئة حول عنصر، اضبط المُعدِّل padding
.
إذا كنت تريد إضافة مساحة فارغة فوق خط أساس النص بحيث تحصل على
مسافة محدّدة من أعلى التنسيق إلى خط الأساس، استخدِم المُعدِّل
paddingFromBaseline
:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
فرق التوقيت
لتحديد موضع تنسيق بالنسبة إلى موضعه الأصلي، أضِف المُعدِّل
offset
واضبط القيمة المُعدَّلة في محورَي x وy.
يمكن أن تكون العناصر غير القابلة للاستبدال موجبة أو غير موجبة. الفرق بين
padding
وoffset
هو أنّ إضافة offset
إلى عنصر تركيبي لا يؤدي إلى
تغيير قياساته:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
يتم تطبيق المُعدِّل offset
أفقيًا وفقًا لاتجاه التنسيق.
في سياق من اليمين إلى اليسار، ينقل القيمة الموجبة offset
العنصر إلى
اليمين، بينما في سياق من اليمين إلى اليسار، ينقل العنصر إلى اليسار.
إذا كنت بحاجة إلى ضبط قيمة إزاحة بدون مراعاة اتجاه التنسيق، اطّلِع على المُعدِّل
absoluteOffset
الذي تؤدي فيه قيمة الإزاحة الموجبة دائمًا إلى نقل العنصر إلى
اليمين.
يقدّم المُعدِّل offset
طريقتَي تحميل زائدتَين: offset
التي تأخذ
المَعلمات كمَعلمات وoffset
التي تأخذ دالة lambda.
للحصول على معلومات أكثر تفصيلاً حول حالات استخدام كل من هذه الإعدادات وكيفية تحسين الأداء، يُرجى الاطّلاع على القسم أداء الإنشاء - تأجيل عمليات القراءة قدر الإمكان.
أمان النطاق في ميزة "الإنشاء"
في ميزة "الإنشاء"، هناك عوامل تعديل لا يمكن استخدامها إلا عند تطبيقها على العناصر الفرعية لعناصر تركيب معيّنة. تفرض ميزة "الإنشاء" ذلك من خلال النطاقات المخصّصة.
على سبيل المثال، إذا كنت تريد جعل الطفل بحجم العنصر Box
بدون
التأثير في حجم Box
، استخدِم المُعدِّل
matchParentSize
. لا يتوفّر matchParentSize
إلا في
BoxScope
.
وبالتالي، لا يمكن استخدامه إلا على حساب طفل ضمن حساب Box
.
تمنع ميزة "أمان النطاق" من إضافة عوامل تعديل لا تعمل في العناصر القابلة للتجميع والنطاقات الأخرى، كما توفّر الوقت الذي قد تقضيه في التجربة والخطأ.
تُرسِل المُعدِّلات على مستوى النطاق إشعارًا للوالد بشأن بعض المعلومات التي يجب أن يعرفها عن الطفل. ويُشار إليها أيضًا بشكل شائع باسم مُعدِّلات البيانات الرئيسية. تختلف وظائفها الداخلية عن وظائف عوامل تعديل العامّة، ولكنّ هذه الاختلافات لا تهمّ من ناحية الاستخدام.
matchParentSize
في Box
كما ذكرنا أعلاه، إذا كنت تريد أن يكون تنسيق العنصر الفرعي بالحجم نفسه لتنسيق العنصر الرئيسي
Box
بدون التأثير في حجم Box
، استخدِم المُعدِّل matchParentSize
.
يُرجى العِلم أنّ سمة matchParentSize
لا تتوفّر إلا ضمن نطاق Box
، ما يعني أنّه
لا تنطبق إلا على العناصر الثانوية المباشرة للعناصر القابلة للتجميع من النوع Box
.
في المثال أدناه، يأخذ العنصر الفرعي Spacer
حجمه من العنصر الرئيسي Box
،
الذي يأخذ حجمه بدوره من أكبر العناصر الفرعية، وهوArtistCard
في هذه الحالة.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
إذا تم استخدام fillMaxSize
بدلاً من matchParentSize
، سيأخذ Spacer
كل المساحة المتاحة المسموح بها للعنصر الرئيسي، ما يؤدي بدوره إلى
توسيع العنصر الرئيسي وملء كل المساحة المتاحة.
weight
في Row
وColumn
كما رأيت في القسم السابق حول المسافة البادئة
والحجم، يتم تحديد الحجم القابل للتركيب تلقائيًا من خلال
المحتوى الذي يُلفّه. يمكنك ضبط حجم عنصر قابل للإنشاء ليكون مرنًا ضمن
العنصر الأصلي باستخدام المُعدِّل weight
الذي لا يتوفّر إلا في RowScope
و
ColumnScope
.
لنأخذ Row
يحتوي على عنصرَي Box
قابلَين للتجميع.
يتم منح المربّع الأول ضعف weight
المربّع الثاني، لذا يتم منحه ضعف
العرض. بما أنّ Row
يبلغ عرضه 210.dp
، يكون عرض Box
الأول 140.dp
، ويكون
عرض Box
الثاني 70.dp
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
استخراج المُعدِّلات وإعادة استخدامها
يمكن ربط عدّة عناصر تعديل معًا لتزيين عنصر تركيبي أو
تعزيزه. يتم إنشاء هذه السلسلة من خلال واجهة Modifier
التي تمثّل قائمة مرتبة وغير قابلة للتغيير من Modifier.Elements
فردية.
يمثّل كل Modifier.Element
سلوكًا فرديًا، مثل سلوكيات التنسيق والرسم
والرسومات، وجميع السلوكيات المتعلّقة بالإيماءات والتركيز والدلالات، بالإضافة
إلى أحداث إدخال الجهاز. يُرجى العِلم أنّ ترتيب العناصر مهمّ، فسيتم تطبيق العناصر المعدِّلة التي تتم إضافتها أولاً.
في بعض الأحيان، قد يكون من المفيد إعادة استخدام نُسخ سلسلة المُعدِّلات نفسها في عناصر قابلة للتجميع متعددة، وذلك من خلال استخراجها إلى متغيّرات ورفعها إلى نطاقات أعلى. ويمكن أن يؤدي ذلك إلى تحسين سهولة قراءة الرمز البرمجي أو المساعدة في تحسين أداء تطبيقك لعدة أسباب:
- لن تتم إعادة تخصيص المُعدِّلات عند إعادة التركيب للعناصر القابلة للتجميع التي تستخدمها
- يمكن أن تكون سلاسل المُعدِّلات طويلة جدًا ومعقدة، لذا يمكن أن يؤدي إعادة استخدام النسخة نفسها من سلسلة إلى تخفيف عبء العمل الذي يجب أن يؤديه وقت تشغيل Compose عند مقارنتها.
- ويعزّز هذا الاستخراج سهولة استخدام الرمز البرمجي واتساقه وقابليته للصيانة في جميع أنحاء قاعدة الرموز البرمجية.
أفضل الممارسات لإعادة استخدام المُعدِّلات
أنشئ سلاسل Modifier
بنفسك واستخرِجها لإعادة استخدامها في عدة
مكونات قابلة للتجميع. لا بأس أبدًا بحفظ مُعدِّل فقط، لأنّه
كائنات تشبه البيانات:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
استخراج عوامل التعديل وإعادة استخدامها عند رصد حالة تتغيّر بشكل متكرّر
عند رصد حالات تتغيّر بشكل متكرّر داخل العناصر القابلة للتجميع، مثل حالات التحريك
أو scrollState
، قد يتم إجراء عدد كبير من عمليات إعادة التركيب. في هذه الحالة، سيتم تخصيص المُعدِّلات لكل عملية إعادة تركيب
وربما لكل إطار:
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
بدلاً من ذلك، يمكنك إنشاء مثيل المُعدِّل نفسه واستخراجه وإعادة استخدامه وإرساله إلى العنصر القابل للتجميع على النحو التالي:
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
استخراج المُعدِّلات غير المحدودة النطاق وإعادة استخدامها
يمكن إزالة نطاق المُعدِّلات أو تحديد نطاق لها في ملف ملف برمجي محدد. في حال استخدام عوامل تعديل غير محددة النطاق، يمكنك استخراجها بسهولة خارج أيّ عناصر قابلة للتجميع كمتغيّرات بسيطة:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
ويمكن أن يكون ذلك مفيدًا بشكل خاص عند دمجه مع التنسيقات المُعدّة للعرض البطيء. في معظم الحالات، ستحتاج إلى أن تتضمّن كلّ العناصر التي قد تكون كبيرة المعدّلات نفسها بالضبط:
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
استخراج المُعدِّلات على مستوى النطاق وإعادة استخدامها
عند التعامل مع المُعدِّلات التي يتمّ تحديد نطاقها لبعض العناصر القابلة للتجميع، يمكنك استخراجها إلى أعلى مستوى ممكن وإعادة استخدامها عند اللزوم:
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
يجب عدم تمرير سوى المُعدِّلات المستخرَجة ذات النطاق إلى العناصر الثانوية المباشرة ذات النطاق نفسه. راجِع قسم أمان النطاق في الإنشاء للحصول على مزيد من المراجع حول أهمية ذلك:
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
المزيد من عمليات ربط المُعدِّلات المستخرَجة
يمكنك ربط سلاسل المُعدِّلات المستخرَجة أو إلحاقها ببعضها من خلال استدعاء الدالة
.then()
:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
يُرجى العِلم أنّ ترتيب عوامل التعديل مهم.
مزيد من المعلومات
نقدّم قائمة كاملة بالمُعدِّلات، مع مَعلماتها ونطاقاتها.
لمزيد من التدريب على كيفية استخدام عوامل التعديل، يمكنك أيضًا الاطّلاع على التصاميم الأساسية في الدرس التطبيقي حول Compose أو الرجوع إلى الآن في مستودع Android.
لمزيد من المعلومات عن المُعدِّلات المخصّصة وكيفية إنشائها، اطّلِع على المستندات حول التنسيقات المخصّصة - استخدام مُعدِّل التنسيق.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون لغة JavaScript غير مفعّلة.
- أساسيات تنسيق الإنشاء
- إجراءات المحرِّر {:#editor-actions}
- التنسيقات المخصّصة {:#custom-layouts }