لیستها به کاربران اجازه میدهند تا یک مورد را از مجموعهای از گزینهها در دستگاههای Wear OS انتخاب کنند.
بسیاری از دستگاههای Wear OS از صفحه نمایشهای گرد استفاده میکنند که دیدن آیتمهای لیست که در نزدیکی بالا و پایین صفحه نمایش ظاهر میشوند را دشوارتر میکند. به همین دلیل، Compose for Wear OS شامل نسخهای از کلاس LazyColumn به نام TransformingLazyColumn است که از انیمیشنهای مقیاسبندی و تغییر شکل پشتیبانی میکند. وقتی آیتمها به لبهها حرکت میکنند، کوچکتر و محو میشوند.
برای اعمال جلوههای مقیاسبندی و پیمایش توصیهشده:
- از
Modifier.transformedHeightاستفاده کنید تا Compose بتواند تغییر ارتفاع را هنگام اسکرول کردن آیتم در صفحه محاسبه کند. - برای اعمال جلوههای بصری، از جمله کوچک کردن محتوای آیتم، از
transformation = SurfaceTransformation(transformationSpec)استفاده کنید. - برای کامپوننتهایی که
transformationبه عنوان پارامتر نمیپذیرند، مانندTextاز یکTransformationSpecسفارشی استفاده کنید.
انیمیشن زیر نشان میدهد که چگونه یک عنصر لیست هنگام نزدیک شدن به بالا و پایین صفحه، تغییر اندازه میدهد و شکل آن تغییر میکند:
قطعه کد زیر نحوه ایجاد یک لیست با استفاده از طرحTransformingLazyColumn را نشان میدهد تا محتوایی ایجاد شود که در اندازههای مختلف صفحه نمایش Wear OS عالی به نظر برسد . این قطعه کد همچنین استفاده از اصلاحکنندهی minimumVerticalContentPadding را نشان میدهد که باید آن را روی آیتمهای لیست تنظیم کنید تا فاصلهی (padding) صحیح در بالا و پایین لیست اعمال شود.
برای نمایش نشانگر اسکرول، 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, ) } } } }
یک افکت ضربه محکم و ناگهانی اضافه کنید
قابلیت Snapping تضمین میکند که وقتی کاربر اسکرول یا حرکت Fling را تمام میکند، لیست با یک آیتم که دقیقاً در یک نقطه خاص، معمولاً مرکز صفحه، قرار گرفته است، تنظیم شود. در صفحههای نمایش گرد، که آیتمها با دور شدن از مرکز، تغییر اندازه میدهند و شکل میگیرند، Snapping به ویژه برای اطمینان از اینکه مرتبطترین آیتم در ناحیه دید بهینه کاملاً قابل مشاهده و خوانا باقی میماند، مفید است. برای افزودن رفتار snap-and-fling، پارامتر 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) ) { // ... // ... } }
طرحبندی معکوس
به طور پیشفرض، یک لیست قابل اسکرول به لبه بالایی خود متصل میشود. اگر کاربر به پایین یک لیست استاندارد اسکرول کرده باشد و یک آیتم جدید به انتهای آن اضافه شود، لیست نمای کاربر را روی آیتم فعلی حفظ میکند. به عنوان مثال، اگر کاربر در حال مشاهده آیتم ۱۰ در پایین صفحه باشد و آیتم ۱۱ اضافه شود، نما روی آیتم ۱۰ متمرکز میماند و آیتم ۱۱ خارج از صفحه و در زیر نمای فعلی ظاهر میشود.
برای مواردی مانند برنامههای پیامرسان یا گزارشهای زنده، این رفتار معمولاً مطلوب نیست. وقتی موارد جدید میرسند، کاربران معمولاً میخواهند آخرین محتوا را فوراً ببینند، اگر در پایین لیست باشند. اگر موارد زیادی به طور همزمان برسند، لیست باید پرش کند تا آخرین مورد را در پایین نمایش دهد (به این معنی که برخی از موارد میانی ممکن است اصلاً نمایش داده نشوند مگر اینکه کاربر به بالا اسکرول کند).
برای پشتیبانی از این موارد استفاده، TransformingLazyColumn به شما امکان میدهد با تنظیم reverseLayout = true ، طرحبندی را معکوس کنید. این کار لنگر لیست را از لبه بالا به لبه پایین تغییر میدهد.
برای راحتی، تنظیم reverseLayout = true ترتیب بصری آیتمها و جهت اسکرول کردن را نیز معکوس میکند:
- آیتمها از پایین به بالا تشکیل میشوند، به این معنی که اندیس ۰ در پایین صفحه نمایش داده میشود.
- با اسکرول کردن به بالا، آیتمهایی با شاخصهای بالاتر نمایش داده میشوند.
برای افزودن رفتار snap-and-fling به همراه طرحبندی معکوس، میتوانید 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") } } } }
تصاویر زیر تفاوت بین یک لیست معمولی و یک لیست معکوس را نشان میدهند:


دکمههای لبهای در لیستها
برای متریال ۳، میتوانید یک 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 به شما امکان میدهد با کشیدن انگشت، به اقدامات مربوط به یک آیتم لیست، مانند Card یا Chip ، دسترسی پیدا کنید. کشیدن انگشت معمولاً یک یا دو دکمه عملیاتی (مانند "حذف" یا "بیشتر") را در کنار صفحه نمایش میدهد.
هنگام استفاده از SwipeToReveal درون یک TransformingLazyColumn ، این دستورالعملها را دنبال کنید:
- تنظیم مجدد هنگام اسکرول : وقتی کاربر لیست را اسکرول میکند، هر آیتمی که با کشیدن انگشت باز شده را به حالت پوشیده شدهاش برمیگرداند.
- ارتفاعهای ثابت : ارتفاع دکمههای عملیاتی را طوری تنظیم کنید که با آیتم داخلی که روی آن کشیده میشود (چه یک
Buttonباشد و چه یکCard) مطابقت داشته باشد تا ظاهری ثابت داشته باشد. - تغییر شکل دادن کانتینر : اصلاحکننده
transformedHeightوtransformationSpecرا روی خود کامپوننتSwipeToRevealاعمال کنید. - تبدیل دوگانه انجام ندهید : اصلاحکنندههای
transformedHeightیاtransformationرا روی آیتم داخلیِ سوایپشده (کارت یا دکمهی داخل کانتینرSwipeToReveal) اعمال نکنید.
ترکیبات سفارشی در لیستها
هنگام ساخت اجزای سطح سفارشی برای TransformingLazyColumn ، این بهترین شیوهها را دنبال کنید تا عناصر قابل ترکیب شما به آرامی در نزدیکی لبههای صفحه نمایش تغییر اندازه، محو شدن و شکل بگیرند:
- Expose
SurfaceTransformation: یک پارامتر اختیاریSurfaceTransformation(با مقدار پیشفرضnull) را میپذیرد که با کامپوننتهای استاندارد Wear Compose Material 3 مانندCardوButtonمطابقت دارد. این به فراخوانیکنندگان در یکTransformingLazyColumnاجازه میدهدSurfaceTransformation(transformationSpec)را ارسال کنند، در حالی که به کامپوننت اجازه میدهد به طور معمول خارج از یک لیست کار کند. - ابتدا در کد فراخوانی
Modifier.transformedHeightاعمال کنید : هنگام قرار دادن composable سفارشی خود در یکTransformingLazyColumn،Modifier.transformedHeight(this, transformationSpec)را به عنوان اولین اصلاحکننده در زنجیره اصلاحکننده کد فراخوانیشده ارسال کنید. در حالی کهSurfaceTransformationجلوههای مقیاسبندی بصری و محو شدن را اعمال میکند،transformedHeightبرای گفتن به طرحبندی لیست برای محاسبه مجدد ارتفاع آیتم هنگام کوچک شدن، بسیار مهم است. - لایههای تبدیل،
modifierفراخوانیکننده و نقاش را به ترتیب اعمال کنید :- لایه تبدیل کانتینر : زنجیره اصلاحکننده کانتینر ریشه را با
Modifier.graphicsLayerشروع کنید وapplyContainerTransformation()، به طوری که هم پسزمینه و هم محتوا در فضای مختصات مقیاسبندی شده و کجشده ترسیم شوند. -
modifierفراخوانیکننده : پارامترmodifierارسالشده توسط فراخوانیکننده (که شاملModifier.transformedHeightمیشود) را در مرحلهی بعد، قبل از هرگونه تغییر اندازه یا فاصلهگذاری داخلی، اعمال کنید. - برش شکل وقتی هیچ تبدیلی وجود ندارد : اگر
transformationnullباشد، قبل از ترسیم پسزمینه،Modifier.clip(shape)را اعمال کنید. نقاش برگردانده شده توسطcreateContainerPainter()خودش را به شکل میچسباند، اما یک نقاش ساده این کار را نمیکند، بنابراین بدون این، پسزمینه با گوشههای مربعی خارج از یک لیست ترسیم میشود. - نقاش پسزمینهی تغییرشکلدهنده : با استفاده از
Modifier.drawBehindو یک نقاش ایجاد شده ازcreateContainerPainter()پسزمینه را درون لایهی ظرف رسم کنید. - لایه تبدیل محتوا : یک لایه دوم
Modifier.graphicsLayerبا استفادهapplyContentTransformation()اعمال کنید و آن را به شکل ظرف بچسبانید تا محتوای داخلی با نزدیک شدن به قاب، زودتر محو شود.
- لایه تبدیل کانتینر : زنجیره اصلاحکننده کانتینر ریشه را با
قطعه کد زیر نحوه پیادهسازی یک BoardingPassCard سفارشی را نشان میدهد که این تبدیلها را به ترتیب اعمال میکند:
@Composable fun BoardingPassCard( flightNumber: String, origin: String, destination: String, gate: String, seat: String, departureTime: String, modifier: Modifier = Modifier, transformation: SurfaceTransformation? = null, shape: Shape = RoundedCornerShape(18.dp), statusBadge: @Composable () -> Unit = {} ) { // 1. Create morphing container painter val backgroundPainter = ColorPainter(MaterialTheme.colorScheme.surfaceContainer) val finalPainter = if (transformation != null) { remember(transformation, backgroundPainter, shape) { transformation.createContainerPainter(backgroundPainter, shape, border = null) } } else { backgroundPainter } Column( modifier = Modifier // 2a. Container layer: Scales, fades, and tilts the whole card surface .then( if (transformation != null) { Modifier.graphicsLayer { transformation.run { applyContainerTransformation() } } } else Modifier ) // 2b. Caller modifier: Includes Modifier.transformedHeight in a list .then(modifier) .fillMaxWidth() // 2c. Shape clip: Only needed without a transformation, because the // painter from createContainerPainter clips itself to the shape .then(if (transformation == null) Modifier.clip(shape) else Modifier) // 2d. Morphing background: Drawn inside the transformed container layer .drawBehind { with(finalPainter) { draw(size) } } // 2e. Content layer: Fades content earlier and clips children to shape .then( if (transformation != null) { Modifier.graphicsLayer { this.shape = shape this.clip = true transformation.run { applyContentTransformation() } } } else Modifier ) .padding(horizontal = 14.dp, vertical = 10.dp) ) { // Card content goes here } }
سپس میتوانید با ارسال Modifier.transformedHeight به عنوان اولین اصلاحکننده، به همراه SurfaceTransformation(transformationSpec) BoardingPassCard درون یک TransformingLazyColumn استفاده کنید:
@Composable fun BoardingPassListSample(flights: List<FlightInfo>) { val listState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold(scrollState = listState) { contentPadding -> TransformingLazyColumn( state = listState, contentPadding = contentPadding, modifier = Modifier.fillMaxSize() ) { items(flights.size) { index -> val flight = flights[index] BoardingPassCard( flightNumber = flight.number, origin = flight.origin, destination = flight.destination, gate = flight.gate, seat = flight.seat, departureTime = flight.time, modifier = Modifier .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( CardDefaults.minimumVerticalListContentPadding ), transformation = SurfaceTransformation(transformationSpec) ) } } } }
برای شما توصیه میشود
- توجه: متن لینک زمانی نمایش داده میشود که جاوا اسکریپت غیرفعال باشد.
- آهنگسازی برای Wear OS Codelab
- لیستها و شبکهها
- استفاده از Viewها در Compose
لیستها به کاربران اجازه میدهند تا یک مورد را از مجموعهای از گزینهها در دستگاههای Wear OS انتخاب کنند.
بسیاری از دستگاههای Wear OS از صفحه نمایشهای گرد استفاده میکنند که دیدن آیتمهای لیست که در نزدیکی بالا و پایین صفحه نمایش ظاهر میشوند را دشوارتر میکند. به همین دلیل، Compose for Wear OS شامل نسخهای از کلاس LazyColumn به نام TransformingLazyColumn است که از انیمیشنهای مقیاسبندی و تغییر شکل پشتیبانی میکند. وقتی آیتمها به لبهها حرکت میکنند، کوچکتر و محو میشوند.
برای اعمال جلوههای مقیاسبندی و پیمایش توصیهشده:
- از
Modifier.transformedHeightاستفاده کنید تا Compose بتواند تغییر ارتفاع را هنگام اسکرول کردن آیتم در صفحه محاسبه کند. - برای اعمال جلوههای بصری، از جمله کوچک کردن محتوای آیتم، از
transformation = SurfaceTransformation(transformationSpec)استفاده کنید. - برای کامپوننتهایی که
transformationبه عنوان پارامتر نمیپذیرند، مانندTextاز یکTransformationSpecسفارشی استفاده کنید.
انیمیشن زیر نشان میدهد که چگونه یک عنصر لیست هنگام نزدیک شدن به بالا و پایین صفحه، تغییر اندازه میدهد و شکل آن تغییر میکند:
قطعه کد زیر نحوه ایجاد یک لیست با استفاده از طرحTransformingLazyColumn را نشان میدهد تا محتوایی ایجاد شود که در اندازههای مختلف صفحه نمایش Wear OS عالی به نظر برسد . این قطعه کد همچنین استفاده از اصلاحکنندهی minimumVerticalContentPadding را نشان میدهد که باید آن را روی آیتمهای لیست تنظیم کنید تا فاصلهی (padding) صحیح در بالا و پایین لیست اعمال شود.
برای نمایش نشانگر اسکرول، 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, ) } } } }
یک افکت ضربه محکم و ناگهانی اضافه کنید
قابلیت Snapping تضمین میکند که وقتی کاربر اسکرول یا حرکت Fling را تمام میکند، لیست با یک آیتم که دقیقاً در یک نقطه خاص، معمولاً مرکز صفحه، قرار گرفته است، تنظیم شود. در صفحههای نمایش گرد، که آیتمها با دور شدن از مرکز، تغییر اندازه میدهند و شکل میگیرند، Snapping به ویژه برای اطمینان از اینکه مرتبطترین آیتم در ناحیه دید بهینه کاملاً قابل مشاهده و خوانا باقی میماند، مفید است. برای افزودن رفتار snap-and-fling، پارامتر 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) ) { // ... // ... } }
طرحبندی معکوس
به طور پیشفرض، یک لیست قابل اسکرول به لبه بالایی خود متصل میشود. اگر کاربر به پایین یک لیست استاندارد اسکرول کرده باشد و یک آیتم جدید به انتهای آن اضافه شود، لیست نمای کاربر را روی آیتم فعلی حفظ میکند. به عنوان مثال، اگر کاربر در حال مشاهده آیتم ۱۰ در پایین صفحه باشد و آیتم ۱۱ اضافه شود، نما روی آیتم ۱۰ متمرکز میماند و آیتم ۱۱ خارج از صفحه و در زیر نمای فعلی ظاهر میشود.
برای مواردی مانند برنامههای پیامرسان یا گزارشهای زنده، این رفتار معمولاً مطلوب نیست. وقتی موارد جدید میرسند، کاربران معمولاً میخواهند آخرین محتوا را فوراً ببینند، اگر در پایین لیست باشند. اگر موارد زیادی به طور همزمان برسند، لیست باید پرش کند تا آخرین مورد را در پایین نمایش دهد (به این معنی که برخی از موارد میانی ممکن است اصلاً نمایش داده نشوند مگر اینکه کاربر به بالا اسکرول کند).
برای پشتیبانی از این موارد استفاده، TransformingLazyColumn به شما امکان میدهد با تنظیم reverseLayout = true ، طرحبندی را معکوس کنید. این کار لنگر لیست را از لبه بالا به لبه پایین تغییر میدهد.
برای راحتی، تنظیم reverseLayout = true ترتیب بصری آیتمها و جهت اسکرول کردن را نیز معکوس میکند:
- آیتمها از پایین به بالا تشکیل میشوند، به این معنی که اندیس ۰ در پایین صفحه نمایش داده میشود.
- با اسکرول کردن به بالا، آیتمهایی با شاخصهای بالاتر نمایش داده میشوند.
برای افزودن رفتار snap-and-fling به همراه طرحبندی معکوس، میتوانید 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") } } } }
تصاویر زیر تفاوت بین یک لیست معمولی و یک لیست معکوس را نشان میدهند:


دکمههای لبهای در لیستها
برای متریال ۳، میتوانید یک 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 به شما امکان میدهد با کشیدن انگشت، به اقدامات مربوط به یک آیتم لیست، مانند Card یا Chip ، دسترسی پیدا کنید. کشیدن انگشت معمولاً یک یا دو دکمه عملیاتی (مانند "حذف" یا "بیشتر") را در کنار صفحه نمایش میدهد.
هنگام استفاده از SwipeToReveal درون یک TransformingLazyColumn ، این دستورالعملها را دنبال کنید:
- تنظیم مجدد هنگام اسکرول : وقتی کاربر لیست را اسکرول میکند، هر آیتمی که با کشیدن انگشت باز شده را به حالت پوشیده شدهاش برمیگرداند.
- ارتفاعهای ثابت : ارتفاع دکمههای عملیاتی را طوری تنظیم کنید که با آیتم داخلی که روی آن کشیده میشود (چه یک
Buttonباشد و چه یکCard) مطابقت داشته باشد تا ظاهری ثابت داشته باشد. - تغییر شکل دادن کانتینر : اصلاحکننده
transformedHeightوtransformationSpecرا روی خود کامپوننتSwipeToRevealاعمال کنید. - تبدیل دوگانه انجام ندهید : اصلاحکنندههای
transformedHeightیاtransformationرا روی آیتم داخلیِ سوایپشده (کارت یا دکمهی داخل کانتینرSwipeToReveal) اعمال نکنید.
ترکیبات سفارشی در لیستها
هنگام ساخت اجزای سطح سفارشی برای TransformingLazyColumn ، این بهترین شیوهها را دنبال کنید تا عناصر قابل ترکیب شما به آرامی در نزدیکی لبههای صفحه نمایش تغییر اندازه، محو شدن و شکل بگیرند:
- Expose
SurfaceTransformation: یک پارامتر اختیاریSurfaceTransformation(با مقدار پیشفرضnull) را میپذیرد که با کامپوننتهای استاندارد Wear Compose Material 3 مانندCardوButtonمطابقت دارد. این به فراخوانیکنندگان در یکTransformingLazyColumnاجازه میدهدSurfaceTransformation(transformationSpec)را ارسال کنند، در حالی که به کامپوننت اجازه میدهد به طور معمول خارج از یک لیست کار کند. - ابتدا در کد فراخوانی
Modifier.transformedHeightاعمال کنید : هنگام قرار دادن composable سفارشی خود در یکTransformingLazyColumn،Modifier.transformedHeight(this, transformationSpec)را به عنوان اولین اصلاحکننده در زنجیره اصلاحکننده کد فراخوانیشده ارسال کنید. در حالی کهSurfaceTransformationجلوههای مقیاسبندی بصری و محو شدن را اعمال میکند،transformedHeightبرای گفتن به طرحبندی لیست برای محاسبه مجدد ارتفاع آیتم هنگام کوچک شدن، بسیار مهم است. - لایههای تبدیل،
modifierفراخوانیکننده و نقاش را به ترتیب اعمال کنید :- لایه تبدیل کانتینر : زنجیره اصلاحکننده کانتینر ریشه را با
Modifier.graphicsLayerشروع کنید وapplyContainerTransformation()، به طوری که هم پسزمینه و هم محتوا در فضای مختصات مقیاسبندی شده و کجشده ترسیم شوند. -
modifierفراخوانیکننده : پارامترmodifierارسالشده توسط فراخوانیکننده (که شاملModifier.transformedHeightمیشود) را در مرحلهی بعد، قبل از هرگونه تغییر اندازه یا فاصلهگذاری داخلی، اعمال کنید. - برش شکل وقتی هیچ تبدیلی وجود ندارد : اگر
transformationnullباشد، قبل از ترسیم پسزمینه،Modifier.clip(shape)را اعمال کنید. نقاش برگردانده شده توسطcreateContainerPainter()خودش را به شکل میچسباند، اما یک نقاش ساده این کار را نمیکند، بنابراین بدون این، پسزمینه با گوشههای مربعی خارج از یک لیست ترسیم میشود. - نقاش پسزمینهی تغییرشکلدهنده : با استفاده از
Modifier.drawBehindو یک نقاش ایجاد شده ازcreateContainerPainter()پسزمینه را درون لایهی ظرف رسم کنید. - لایه تبدیل محتوا : یک لایه دوم
Modifier.graphicsLayerبا استفادهapplyContentTransformation()اعمال کنید و آن را به شکل ظرف بچسبانید تا محتوای داخلی با نزدیک شدن به قاب، زودتر محو شود.
- لایه تبدیل کانتینر : زنجیره اصلاحکننده کانتینر ریشه را با
قطعه کد زیر نحوه پیادهسازی یک BoardingPassCard سفارشی را نشان میدهد که این تبدیلها را به ترتیب اعمال میکند:
@Composable fun BoardingPassCard( flightNumber: String, origin: String, destination: String, gate: String, seat: String, departureTime: String, modifier: Modifier = Modifier, transformation: SurfaceTransformation? = null, shape: Shape = RoundedCornerShape(18.dp), statusBadge: @Composable () -> Unit = {} ) { // 1. Create morphing container painter val backgroundPainter = ColorPainter(MaterialTheme.colorScheme.surfaceContainer) val finalPainter = if (transformation != null) { remember(transformation, backgroundPainter, shape) { transformation.createContainerPainter(backgroundPainter, shape, border = null) } } else { backgroundPainter } Column( modifier = Modifier // 2a. Container layer: Scales, fades, and tilts the whole card surface .then( if (transformation != null) { Modifier.graphicsLayer { transformation.run { applyContainerTransformation() } } } else Modifier ) // 2b. Caller modifier: Includes Modifier.transformedHeight in a list .then(modifier) .fillMaxWidth() // 2c. Shape clip: Only needed without a transformation, because the // painter from createContainerPainter clips itself to the shape .then(if (transformation == null) Modifier.clip(shape) else Modifier) // 2d. Morphing background: Drawn inside the transformed container layer .drawBehind { with(finalPainter) { draw(size) } } // 2e. Content layer: Fades content earlier and clips children to shape .then( if (transformation != null) { Modifier.graphicsLayer { this.shape = shape this.clip = true transformation.run { applyContentTransformation() } } } else Modifier ) .padding(horizontal = 14.dp, vertical = 10.dp) ) { // Card content goes here } }
سپس میتوانید با ارسال Modifier.transformedHeight به عنوان اولین اصلاحکننده، به همراه SurfaceTransformation(transformationSpec) BoardingPassCard درون یک TransformingLazyColumn استفاده کنید:
@Composable fun BoardingPassListSample(flights: List<FlightInfo>) { val listState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold(scrollState = listState) { contentPadding -> TransformingLazyColumn( state = listState, contentPadding = contentPadding, modifier = Modifier.fillMaxSize() ) { items(flights.size) { index -> val flight = flights[index] BoardingPassCard( flightNumber = flight.number, origin = flight.origin, destination = flight.destination, gate = flight.gate, seat = flight.seat, departureTime = flight.time, modifier = Modifier .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( CardDefaults.minimumVerticalListContentPadding ), transformation = SurfaceTransformation(transformationSpec) ) } } } }
برای شما توصیه میشود
- توجه: متن لینک زمانی نمایش داده میشود که جاوا اسکریپت غیرفعال باشد.
- آهنگسازی برای Wear OS Codelab
- لیستها و شبکهها
- استفاده از Viewها در Compose