تتيح لك المعدِّلات تزيين عنصر قابل للإنشاء أو تحسينه. تتيح لك المعدِّلات تنفيذ أنواع الإجراءات التالية:
- تغيير حجم العنصر القابل للإنشاء وتنسيقه وسلوكه ومظهره
- إضافة معلومات، مثل تصنيفات تسهيل الاستخدام
- معالجة بيانات أدخلها المستخدم
- إضافة تفاعلات عالية المستوى، مثل جعل عنصر قابلاً للنقر أو التمرير أو السحب أو التكبير
المعدِّلات هي عناصر 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، تقبل العناصر مَعلمة Modifier وتلتزم بها.
ترتيب المعدِّلات مهم
ترتيب دوال المعدِّل مهم. بما أنّ كل دالة تُجري تغييرات على 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
تلتف التصميمات المتوفّرة في Compose حول العناصر التابعة لها تلقائيًا. ومع ذلك، يمكنك ضبط حجم باستخدام المعدِّل 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
(توفّر Compose أيضًا 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
الموجب إلى نقل العنصر إلى اليمين، بينما يؤدي offset
الموجب في سياق من اليمين إلى اليسار إلى نقل العنصر إلى اليسار.
إذا كنت بحاجة إلى ضبط إزاحة بدون مراعاة اتجاه التنسيق، اطّلِع على المعدِّل
absoluteOffset
،
حيث تؤدي قيمة الإزاحة الموجبة دائمًا إلى نقل العنصر إلى
اليسار.
يوفّر المعدِّل offset
حمولتين زائدتين، هما offset
التي تأخذ الإزاحات كمعلَمات، وoffset
التي تأخذ تعبير lambda.
للحصول على معلومات أكثر تفصيلاً حول الحالات التي يجب فيها استخدام كل من هذه الطرق وكيفية تحسين الأداء، يُرجى قراءة قسم أداء Compose - تأجيل عمليات القراءة لأطول فترة ممكنة.
أمان النطاق في Compose
في Compose، هناك معدِّلات لا يمكن استخدامها إلا عند تطبيقها على عناصر فرعية من عناصر قابلة للإنشاء معيّنة. تفرض Compose ذلك من خلال النطاقات المخصّصة.
على سبيل المثال، إذا أردت أن يكون حجم العنصر التابع مساويًا لحجم العنصر الرئيسي 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 ) }
ويمكن أن يكون هذا مفيدًا بشكل خاص عند دمجه مع Lazy layouts. في معظم الحالات، من المفترض أن تتضمّن جميع السلع، التي قد يكون عددها كبيرًا، المعدّلات نفسها بالضبط:
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 // ... ) // ... }
يجب تمرير المعدِّلات المستخرَجة والمحدّدة النطاق إلى العناصر الثانوية المباشرة التي لها النطاق نفسه فقط. يمكنك الاطّلاع على القسم أمان النطاق في Compose للحصول على مزيد من المعلومات حول أهمية ذلك:
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 أو الرجوع إلى مستودع Now in Android.
لمزيد من المعلومات حول المعدِّلات المخصّصة وكيفية إنشائها، يمكنك الاطّلاع على المستندات حول التنسيقات المخصّصة - استخدام معدِّل التنسيق.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة
- أساسيات تصميم صفحة الإنشاء
- إجراءات المحرّر {:#editor-actions}
- التنسيقات المخصّصة {:#custom-layouts }