فهرستها به کاربران امکان میدهند موردی را از مجموعهای از انتخابها در دستگاههای Wear OS انتخاب کنند.
بسیاری از دستگاههای Wear OS از صفحهنمایش گرد استفاده میکنند که باعث میشود دیدن
موارد فهرست که در نزدیکی بالای صفحه و پایین صفحه ظاهر میشوند دشوارتر شود. به همین دلیل،
Compose for Wear OS شامل نسخهای از کلاس LazyColumn بهنام
TransformingLazyColumn است که از پویانماییهای تغییر شکل و مقیاسبندی پشتیبانی میکند.
وقتی موارد به لبهها میرسند، کوچکتر میشوند و محو میشوند.
برای اعمال جلوههای پیمایش و مقیاسبندی توصیهشده:
- از
Modifier.transformedHeightاستفاده کنید تا به «نگارش» اجازه دهید تغییر ارتفاع را هنگام پیمایش مورد در صفحه محاسبه کند. - از
transformation = SurfaceTransformation(transformationSpec)برای اعمال جلوههای دیداری، ازجمله کوچک کردن محتوای مورد، استفاده کنید. - برای عناصری که
transformationرا بهعنوان پارامتر نمیپذیرند، مثلText، ازTransformationSpecسفارشی استفاده کنید.
پویانمایی زیر نشان میدهد که عنصر فهرست چگونه با نزدیک شدن به بالای صفحه و پایین صفحه مقیاسبندی میشود و شکل آن تغییر میکند:
تکهکد زیر نشان میدهد که چگونه بااستفاده از چیدمان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) ) { // ... // ... } }
معکوس کردن چیدمان
بهطور پیشفرض، فهرست پیمایشپذیر به لبه بالایی خود متصل میشود. اگر کاربری به پایین فهرست استانداردی پیمایش کرده باشد و مورد جدیدی به انتهای آن اضافه شود، فهرست نمای کاربر را در مورد فعلی حفظ میکند. برای مثال، اگر کاربر درحال مشاهده مورد ۱۰ در پایین صفحه باشد و مورد ۱۱ اضافه شود، نمای مورد ۱۰ همچنان در کانون توجه باقی میماند و مورد ۱۱ در خارج از صفحه در زیر نمای فعلی ظاهر میشود.
برای موارد استفادهای مانند برنامههای پیامرسانی یا گزارشهای زنده، معمولاً این رفتار مطلوب نیست. وقتی موارد جدیدی اضافه میشود، کاربران معمولاً میخواهند جدیدترین محتوا را بلافاصله ببینند، اگر ازقبل در پایین فهرست باشند. اگر موارد زیادی بهطور همزمان برسند، فهرست باید از نمایش موارد میانی صرفنظر کند و جدیدترین مورد را در پایین نمایش دهد (یعنی ممکن است برخیاز موارد میانی اصلاً نمایش داده نشوند، مگر اینکه کاربر به بالا پیمایش کند).
برای پشتیبانی از این موارد استفاده، TransformingLazyColumn به شما امکان میدهد با تنظیم reverseLayout = true، چیدمان را معکوس کنید. این کار لنگر فهرست را از
لبه بالا به لبه پایین تغییر میدهد.
برای راحتی، تنظیم reverseLayout = true همچنین ترتیب دیداری
موارد و جهت اشارههای پیمایش را معکوس میکند:
- موارد از پایین به بالا ترکیب میشوند، یعنی شاخص ۰ در پایین صفحه نمایش داده میشود.
- پیمایش به بالا موارد با شاخصهای بالاتر را نشان میدهد.
برای افزودن رفتار چسباندن و پرتاب کردن همراه با چیدمان معکوس، میتوانید
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، این روالهای مطلوب را دنبال کنید تا عناصر ترکیبی شما در نزدیکی لبههای نمایشگر بهنرمی مقیاسبندی، محو، و تغییر شکل دهند:
- نمایش
SurfaceTransformation: پارامتر اختیاریSurfaceTransformationرا بپذیرید (پیشفرضnull)، با عناصر استاندارد Wear Compose Material 3 مانندCardوButtonمطابقت دارد. این کار به تماسگیرندگان اجازه میدهد درTransformingLazyColumnگذرSurfaceTransformation(transformationSpec)کنند و درعینحال به عنصر اجازه میدهد خارج از فهرست بهطور عادی کار کند. - ابتدا
Modifier.transformedHeightرا در کد فراخوانی اعمال کنید: هنگام قرار دادن ترکیبپذیر سفارشی درTransformingLazyColumn،Modifier.transformedHeight(this, transformationSpec)را بهعنوان اولین اصلاحگر در زنجیره اصلاحگر کد فراخوانی بگذرانید. درحالیکهSurfaceTransformationجلوههای محو شدن و مقیاسبندی دیداری را اعمال میکند،transformedHeightبرای اینکه به چیدمان فهرست بگوید ارتفاع مورد را با کوچک شدن آن دوباره محاسبه کند ضروری است. - اعمال لایههای تبدیل، تماسگیرنده
modifier، و نقاش بهترتیب:- لایه تبدیل محتوی: زنجیره اصلاحکننده محتوی ریشه را با
Modifier.graphicsLayerوapplyContainerTransformation()شروع کنید تا هم پسزمینه و هم محتوا در فضای مختصات مقیاسبندیشده و کجشده رسم شوند. - تماسگیرنده
modifier: پارامترmodifierارسالشده توسط تماسگیرنده (که شاملModifier.transformedHeightمیشود) را قبلاز هرگونه اندازه داخلی یا حاشیه داخلی اعمال کنید. - شکلدهی کلیپ وقتی تبدیل وجود ندارد: اگر
transformationکمتر ازnullاست،Modifier.clip(shape)را قبلاز کشیدن پسزمینه اعمال کنید. نقاش برگشتی باcreateContainerPainter()خود را به شکل میچسباند، اما نقاش ساده این کار را نمیکند، بنابراین بدون این، پسزمینه با گوشههای مربعی در خارج از فهرست رسم میشود. - نقاش پسزمینه تغییر شکلدهنده: پسزمینه را در لایه
ظرف بااستفاده از
Modifier.drawBehindو نقاشی که ازcreateContainerPainter()ایجاد شده است بکشید. - لایه تبدیل محتوا: با
applyContentTransformation()و کلیپModifier.graphicsLayerدوم را به شکل محتوی اعمال کنید تا محتوای داخلی با نزدیک شدن به قاب زودتر محو شود.
- لایه تبدیل محتوی: زنجیره اصلاحکننده محتوی ریشه را با
تکهکد زیر نحوه پیادهسازی 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) ) } } } }
توصیهشده برای شما
- توجه: نوشتار پیوند وقتی جاوا اسکریپت خاموش است نمایش داده میشود
- Codelab مربوط به Compose برای Wear OS
- فهرستها و جدولها
- استفاده از «نماها» در «نوشتن»