تتيح لك المُعدِّلات تزيين عنصر قابل للتجميع أو تحسينه. تتيح لك المعدِّلات القيام بهذه الأنواع من الأشياء:
- تغيير حجم العنصر القابل للتجميع وتنسيقه وسلوكه ومظهره
- إضافة معلومات، مثل تصنيفات تسهيل الاستخدام
- معالجة بيانات المستخدم
- إضافة تفاعلات عالية المستوى، مثل جعل عنصر قابلاً للنقر أو التمرير أو السحب أو التكبير/التصغير
المُعدِّلات هي عناصر 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
، والثاني هو 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 }