يوفّر المعدِّلان
verticalScroll
و
horizontalScroll
أبسط طريقة للسماح للمستخدم بتمرير عنصر عندما
تكون حدود محتوياته أكبر من قيود الحجم الأقصى. باستخدام المعدِّلين verticalScroll وhorizontalScroll، لن تحتاجوا إلى ترجمة المحتويات أو إزاحتها.
@Composable private fun ScrollBoxes() { Column( modifier = Modifier .background(Color.LightGray) .size(100.dp) .verticalScroll(rememberScrollState()) ) { repeat(10) { Text("Item $it", modifier = Modifier.padding(2.dp)) } } }
تتيح لكم ScrollState
تغيير موضع التمرير أو الحصول على حالته الحالية. لإنشائها
باستخدام المَعلمات التلقائية، استخدِموا
rememberScrollState().
@Composable private fun ScrollBoxesSmooth() { // Smoothly scroll 100px on first composition val state = rememberScrollState() LaunchedEffect(Unit) { state.animateScrollTo(100) } Column( modifier = Modifier .background(Color.LightGray) .size(100.dp) .padding(horizontal = 8.dp) .verticalScroll(state) ) { repeat(10) { Text("Item $it", modifier = Modifier.padding(2.dp)) } } }
معدِّل المنطقة القابلة للتمرير
المعدِّل scrollableArea هو وحدة أساسية لإنشاء
حاويات مخصّصة قابلة للتمرير. يوفّر تجريدًا أعلى مستوى من عنصر التعديل
scrollable، ويتعامل مع المتطلبات الشائعة، مثل تفسير التغييرات في الإيماءات
واقتصاص المحتوى وتأثيرات تجاوز حد التمرير.
في حين أنّ scrollableArea يُستخدَم في عمليات التنفيذ المخصّصة، ننصحكم عمومًا
بتفضيل الحلول الجاهزة، مثل verticalScroll أو horizontalScroll
أو العناصر القابلة للإنشاء، مثل LazyColumn لقوائم التمرير العادية. تكون هذه المكوّنات ذات المستوى الأعلى أبسط لحالات الاستخدام الشائعة، وقد تم إنشاؤها باستخدام scrollableArea.
الفرق بين المعدِّلين scrollableArea وscrollable
يكمن الاختلاف الرئيسي بين scrollableArea وscrollable في طريقة تفسير إيماءات التمرير التي يجريها المستخدم:
scrollable(دلتا أولية): تعكس الدلتا مباشرةً الحركة الفعلية لإدخال المستخدم (مثل سحب المؤشر) على الشاشة.scrollableArea(التغيير الموجّه نحو المحتوى): يتم عكسdeltaدلاليًا لتمثيل التغيير المحدّد في موضع التمرير لجعل المحتوى يبدو وكأنّه يتحرّك مع إيماءة المستخدم، وهو عادةً عكس حركة المؤشر.
يمكنكم التفكير في الأمر على النحو التالي: scrollable يخبركم بكيفية تحرّك المؤشر، بينما
scrollableArea يترجم حركة المؤشر هذه إلى كيفية تحرّك الـ محتوى داخل طريقة عرض عادية قابلة للتمرير. هذا العكس هو السبب في أنّ scrollableArea يبدو أكثر طبيعية عند تنفيذ حاوية عادية قابلة للتمرير.
يلخّص الجدول التالي علامات التغيير في السيناريوهات الشائعة:
إيماءة المستخدم |
التغيير الذي يتم إرساله إلى |
التغيير الذي يتم إرساله إلى |
|---|---|---|
تحرّك المؤشر للأعلى |
سالب |
موجب |
تحرّك المؤشر للأسفل |
موجب |
سالب |
تحرّك المؤشر لليسار |
سالب |
موجب (سالب للغة العربية) |
تحرّك المؤشر لليمين |
موجب |
سالب (موجب للغة العربية) |
(*) ملاحظة حول علامة التغيير في scrollableArea: ليست علامة التغيير من
scrollableArea مجرد عكس بسيط. فهي تأخذ في الاعتبار بذكاء ما يلي:
- الاتجاه: عمودي أو أفقي
LayoutDirection: من اليمين إلى اليسار أو من اليسار إلى اليمين (مهم بشكل خاص للتمرير الأفقي)- العلامة
reverseScrolling: ما إذا كان اتجاه التمرير معكوسًا
بالإضافة إلى عكس التغيير في التمرير، يقتصّ scrollableArea أيضًا المحتوى ضمن حدود التنسيق ويتعامل مع عرض تأثيرات تجاوز حد التمرير. تلقائيًا، يستخدم التأثير الذي يوفّره LocalOverscrollFactory.
يمكنكم تخصيص هذا التأثير أو إيقافه باستخدام التحميل الزائد لـ scrollableArea الذي يقبل مَعلمة OverscrollEffect.
متى يجب استخدام المعدِّل scrollableArea؟
يجب استخدام المعدِّل scrollableArea عندما تحتاجون إلى إنشاء مكوّن تمرير مخصّص لا يلبّي احتياجاتكم بشكل كافٍ من خلال المعدِّلين horizontalScroll أو verticalScroll أو تنسيقات Lazy. غالبًا ما يتضمّن ذلك الحالات التالية:
- منطق التنسيق المخصّص: عندما يتغيّر ترتيب العناصر ديناميكيًا استنادًا إلى موضع التمرير
- التأثيرات المرئية الفريدة: تطبيق عمليات التحويل أو تغيير الحجم أو التأثيرات الأخرى على العناصر الثانوية أثناء تمريرها
- التحكّم المباشر: الحاجة إلى تحكّم دقيق في آليات التمرير
بما يتجاوز ما يعرضه
verticalScrollأو تنسيقات Lazy
إنشاء قوائم مخصّصة تشبه العجلة باستخدام scrollableArea
يعرض المثال التالي استخدام scrollableArea لإنشاء قائمة عمودية مخصّصة يتم فيها تصغير حجم العناصر كلما ابتعدت عن المنتصف، ما يؤدي إلى إنشاء تأثير مرئي "يشبه العجلة". هذا النوع من عمليات التحويل المستندة إلى التمرير هو حالة استخدام مثالية لـ scrollableArea.
scrollableArea
@Composable private fun ScrollableAreaSample() { // ... Layout( modifier = Modifier .size(150.dp) .scrollableArea(scrollState, Orientation.Vertical) .background(Color.LightGray), // ... ) { measurables, constraints -> // ... // Update the maximum scroll value to not scroll beyond limits and stop when scroll // reaches the end. scrollState.maxValue = (totalHeight - viewportHeight).coerceAtLeast(0) // Position the children within the layout. layout(constraints.maxWidth, viewportHeight) { // The current vertical scroll position, in pixels. val scrollY = scrollState.value val viewportCenterY = scrollY + viewportHeight / 2 var placeableLayoutPositionY = 0 placeables.forEach { placeable -> // This sample applies a scaling effect to items based on their distance // from the center, creating a wheel-like effect. // ... // Place the item horizontally centered with a layer transformation for // scaling to achieve wheel-like effect. placeable.placeRelativeWithLayer( x = constraints.maxWidth / 2 - placeable.width / 2, // Offset y by the scroll position to make placeable visible in the viewport. y = placeableLayoutPositionY - scrollY, ) { scaleX = scaleFactor scaleY = scaleFactor } // Move to the next item's vertical position. placeableLayoutPositionY += placeable.height } } } } // ...
معدِّل قابل للتمرير
يختلف المعدِّل
scrollable
عن معدِّلات التمرير الأخرى في أنّه scrollable يرصد إيماءات
التمرير ويسجّل التغييرات، ولكنّه لا يزيح محتوياته
تلقائيًا. بدلاً من ذلك، يتم تفويض هذه المهمة إلى المستخدم من خلال
ScrollableState
، وهو مطلوب لكي يعمل هذا المعدِّل بشكل صحيح.
عند إنشاء ScrollableState، يجب توفير دالة consumeScrollDelta التي سيتم استدعاؤها في كل خطوة تمرير (من خلال إدخال الإيماءة أو التمرير السلس أو التحريك السريع) مع التغيير بالبكسل. يجب أن تعرض هذه الدالة مقدار مسافة التمرير المستهلكة، لضمان نشر الحدث بشكل صحيح في الحالات التي تتضمّن عناصر متداخلة تحتوي على المعدِّل scrollable.
يرصد الرمز التالي الإيماءات ويعرض قيمة رقمية للإزاحة، ولكنّه لا يزيح أي عناصر:
@Composable private fun ScrollableSample() { // actual composable state var offset by remember { mutableFloatStateOf(0f) } Box( Modifier .size(150.dp) .scrollable( orientation = Orientation.Vertical, // Scrollable state: describes how to consume // scrolling delta and update offset state = rememberScrollableState { delta -> offset += delta delta } ) .background(Color.LightGray), contentAlignment = Alignment.Center ) { Text(offset.toString()) } }
مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عند إيقاف JavaScript
- التعرّف على الإيماءات
- نقل
CoordinatorLayoutإلى Compose - استخدام طرق العرض في Compose