تتيح القوائم للمستخدمين اختيار عنصر من مجموعة خيارات على أجهزة Wear OS.
تستخدم العديد من أجهزة Wear OS شاشات مستديرة، ما يجعل رؤية عناصر القائمة التي تظهر بالقرب من أعلى الشاشة وأسفلها أكثر صعوبة. لهذا السبب،
يتضمّن Compose for Wear OS إصدارًا من فئة LazyColumn يُسمّى
TransformingLazyColumn، والذي يتيح تأثيرات تغيير الحجم والتحوّل.
عندما تنتقل العناصر إلى الحواف، تصبح أصغر وتتلاشى.
لتطبيق تأثيرات تغيير الحجم والتمرير المقترَحة، اتّبِع الخطوات التالية:
- استخدِم
Modifier.transformedHeightللسماح لـ Compose بحساب تغيير الارتفاع أثناء تمرير العنصر على الشاشة. - استخدِم
transformation = SurfaceTransformation(transformationSpec)لتطبيق التأثيرات المرئية، بما في ذلك تصغير محتويات العنصر. - استخدِم
TransformationSpecمخصّصًا للمكوّنات التي لا تأخذtransformationكمعلَمة، مثلText.
يعرض الرسم المتحرّك التالي كيفية تغيير حجم عنصر قائمة وتغيير شكله عند الاقتراب من أعلى الشاشة وأسفلها:
يعرض مقتطف الرمز التالي كيفية إنشاء قائمة باستخدامTransformingLazyColumn تنسيق لإنشاء محتوى
يبدو رائعًا على مجموعة متنوّعة من أحجام شاشات Wear OS.
يوضّح المقتطف أيضًا استخدام المعدِّل minimumVerticalContentPadding، الذي يجب ضبطه على عناصر القائمة لتطبيق مساحة العرض الداخلية الصحيحة في أعلى القائمة وأسفلها.
لعرض مؤشر التمرير، شارِك columnState بين ScreenScaffold وTransformingLazyColumn:
val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding), transformation = SurfaceTransformation(transformationSpec) ) { Text(text = "Header") } } // ... other items item { Button( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding), transformation = SurfaceTransformation(transformationSpec), onClick = { /* ... */ }, icon = { Icon( imageVector = Icons.Default.Build, contentDescription = "build", ) }, ) { Text( text = "Build", maxLines = 1, overflow = TextOverflow.Ellipsis, ) } } } }
إضافة تأثير "الالتقاط والتحريك السريع"
يضمن الالتقاط أنه عندما يُنهي المستخدم إيماءة التمرير أو التحريك السريع، تستقر القائمة مع وضع عنصر في نقطة معيّنة بدقة، وعادةً ما تكون في منتصف الشاشة. على الشاشات المستديرة، حيث يتم تغيير حجم العناصر وتغيير شكلها أثناء تحرّكها بعيدًا عن المنتصف، يكون الالتقاط مفيدًا بشكل خاص لضمان بقاء العنصر الأكثر صلةً مرئيًا وقابلاً للقراءة بالكامل في منطقة العرض المثالية.لإضافة سلوك "الالتقاط والتحريك السريع"، اضبط المَعلمة flingBehavior على TransformingLazyColumnDefaults.snapFlingBehavior(columnState).
اضبط rotaryScrollableBehavior على القيمة المطابقة، باستخدام RotaryScrollableDefaults.snapBehavior(columnState) للحصول على تجربة متّسقة عند استخدام زر الساعة أو الإطار المادي.
val columnState = rememberTransformingLazyColumnState() ScreenScaffold(scrollState = columnState) { contentPadding -> TransformingLazyColumn( state = columnState, flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState), rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(columnState) ) { // ... // ... } }
التنسيق العكسي
تستند القائمة القابلة للتمرير تلقائيًا إلى حافتها العلوية. إذا مرّر المستخدم إلى أسفل قائمة عادية وتمت إضافة عنصر جديد إلى النهاية، تحتفظ القائمة بعرض المستخدم للعنصر الحالي. على سبيل المثال، إذا كان المستخدم يعرض العنصر 10 في أسفل الشاشة، وتمت إضافة العنصر 11، سيظل العرض مركّزًا على العنصر 10، وسيظهر العنصر 11 خارج الشاشة أسفل العرض الحالي.
بالنسبة إلى حالات الاستخدام مثل تطبيقات المراسلة أو السجلات المباشرة، لا يكون هذا السلوك مطلوبًا عادةً. عند وصول عناصر جديدة، يريد المستخدمون عادةً الاطّلاع على أحدث المحتوى على الفور إذا كانوا في أسفل القائمة. إذا وصل العديد من العناصر في وقت واحد، يجب أن تنتقل القائمة لعرض أحدث عنصر في الأسفل (ما يعني أنّه قد لا يتم عرض بعض العناصر الوسيطة على الإطلاق ما لم يمرّر المستخدم للأعلى).
لدعم حالات الاستخدام هذه، يتيح لك TransformingLazyColumn عكس التنسيق من خلال ضبط reverseLayout = true. يغيّر هذا الإعداد نقطة ارتساء القائمة من الحافة العلوية إلى الحافة السفلية.
لتسهيل الأمر، يؤدي ضبط reverseLayout = true أيضًا إلى عكس الترتيب المرئي للعناصر واتجاه إيماءات التمرير:
- يتم إنشاء العناصر من الأسفل إلى الأعلى، ما يعني أنّ الفهرس 0 يظهر في أسفل الشاشة.
- يكشف التمرير للأعلى عن العناصر ذات الفهارس الأعلى.
لإضافة سلوك "الالتقاط والتحريك السريع" بالإضافة إلى التنسيق العكسي، يمكنك دمج flingBehavior وrotaryScrollableBehavior كما هو موضّح في المقتطف التالي:
val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold(scrollState = columnState) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding, reverseLayout = true, modifier = Modifier.fillMaxWidth() ) { items(10) { index -> Button( label = { Text( text = "Item ${index + 1}" ) }, onClick = {}, modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding), transformation = SurfaceTransformation(transformationSpec) ) } item { // With reverseLayout = true, the last item declared appears at the top. ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding), transformation = SurfaceTransformation(transformationSpec) ) { Text("Header") } } } }
تعرض الصورتان التاليتان الفرق بين قائمة عادية وقائمة معكوسة:
أزرار الحافة في القوائم
بالنسبة إلى Material 3، يمكنك إضافة EdgeButton، وهو زر يلتصق بالحافة في أسفل القوائم. ومع ذلك، احرص على عدم إضافة هذا الزر كعنصر ضمن TransformingLazyColumn، ولكن بدلاً من ذلك استخدِم موضع edgeButton في ScreenScaffold.
يضمن استخدام موضع edgeButton وضع الزر بشكل صحيح في أسفل الشاشة وسلوكه بشكل مناسب عند تمرير القائمة.
يعرض مقتطف الرمز التالي كيفية تنفيذ EdgeButton:
val columnState = rememberTransformingLazyColumnState() ScreenScaffold( scrollState = columnState, edgeButton = { EdgeButton( onClick = { /* TODO */ }, modifier = Modifier.scrollable( columnState, orientation = Orientation.Vertical, reverseDirection = true, // Apply overscroll to the EdgeButton for proper scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ) ) { Text("More") } } ) { contentPadding -> TransformingLazyColumn( contentPadding = contentPadding, state = columnState, ) { // ... // ... } }
مكوّن SwipeToReveal في القوائم
يتيح لك مكوّن SwipeToReveal الوصول إلى إجراءات عنصر قائمة، مثل
a Card أو Chip، من خلال التمرير سريعًا. يكشف التمرير سريعًا عادةً عن زرَّي إجراء أو أكثر (مثل "حذف" أو "المزيد") من الجانب.
عند استخدام SwipeToReveal ضمن TransformingLazyColumn، اتّبِع الإرشادات التالية:
- إعادة الضبط عند التمرير: عندما يمرّر المستخدم القائمة، أعِد ضبط أي عناصر تم فتحها من خلال التمرير سريعًا إلى حالتها المغطّاة.
- ارتفاعات متّسقة: اضبط ارتفاعات أزرار الإجراءات لتتطابق مع العنصر الداخلي
الذي تم تمريره سريعًا (سواء كان
ButtonأوCard) لضمان الحصول على مظهر متّسق. - تغيير شكل الحاوية: طبِّق المعدِّل
transformedHeightوtransformationSpecعلى المكوّنSwipeToRevealنفسه. - عدم تغيير الشكل مرّتين: لا تطبِّق
transformedHeightأوtransformationالمعدِّلات على العنصر الداخلي الذي تم تمريره سريعًا (البطاقة أو الزر داخل حاويةSwipeToReveal).
مُقترَحة لك
- ملاحظة: يظهر نص الرابط عندما يكون JavaScript غير مفعّل
- درس تطبيقي حول الترميز: Compose for Wear OS
- القوائم والشبكات
- استخدام طرق العرض في Compose