Listeler, kullanıcıların Wear OS cihazlarda bir dizi seçenek arasından öğe seçmesine olanak tanır.
Birçok Wear OS cihazda yuvarlak ekran kullanıldığından ekranın üst ve alt kısımlarında görünen liste öğelerini görmek daha zordur. Bu nedenle, Wear OS için Oluşturma'da LazyColumn sınıfının TransformingLazyColumn adlı bir sürümü bulunur. Bu sürüm, ölçeklendirme ve şekil değiştirme animasyonlarını destekler.
Kenarlara doğru hareket eden öğeler küçülür ve soluklaşır.
Önerilen ölçeklendirme ve kaydırma efektlerini uygulamak için:
- Öğe ekranda kaydırılırken Oluştur'un yükseklik değişikliğini hesaplamasına izin vermek için
Modifier.transformedHeightkullanın. - Öğe içeriklerini küçültme de dahil olmak üzere görsel efektleri uygulamak için
transformation = SurfaceTransformation(transformationSpec)simgesini kullanın. transformationparametresini almayan bileşenler (ör.Text) için özel birTransformationSpeckullanın.
Aşağıdaki animasyonda, bir liste öğesinin ekranın üst ve alt kısımlarına yaklaştığında nasıl ölçeklendiği ve şekil değiştirdiği gösterilmektedir:
Aşağıdaki kod snippet'inde,TransformingLazyColumn düzenini kullanarak çeşitli Wear OS ekran boyutlarında harika görünen içerikler oluşturmak için nasıl liste oluşturulacağı gösterilmektedir.
Snippet'te, listenin üst ve alt kısmında doğru dolguyu uygulamak için liste öğelerinde ayarlamanız gereken minimumVerticalContentPadding değiştiricisinin kullanımı da gösterilmektedir.
Kaydırma göstergesini göstermek için ScreenScaffold ile TransformingLazyColumn arasındaki columnState değerini paylaşın:
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, ) } } } }
Snap-and-fling efekti ekleme
Sabitleme, kullanıcının kaydırma veya hızlıca kaydırma hareketini tamamladığında listenin, genellikle ekranın ortası olmak üzere belirli bir noktada tam olarak konumlandırılmış bir öğeyle yerleşmesini sağlar. Öğelerin merkezden uzaklaştıkça ölçeklendiği ve şekil değiştirdiği yuvarlak ekranlarda, en alakalı öğenin en iyi görüntüleme alanında tamamen görünür ve okunabilir kalmasını sağlamak için tutturma özelliği özellikle kullanışlıdır.Bir yapıştır ve fırlat davranışı eklemek için flingBehavior parametresini TransformingLazyColumnDefaults.snapFlingBehavior(columnState) olarak ayarlayın.
Fiziksel ayar düğmesi veya çerçeve kullanılırken tutarlı bir deneyim için RotaryScrollableDefaults.snapBehavior(columnState) simgesini kullanarak rotaryScrollableBehavior simgesini eşleşecek şekilde ayarlayın.
val columnState = rememberTransformingLazyColumnState() ScreenScaffold(scrollState = columnState) { contentPadding -> TransformingLazyColumn( state = columnState, flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState), rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(columnState) ) { // ... // ... } }
Ters düzen
Kaydırılabilir bir liste varsayılan olarak üst kenarına sabitlenir. Bir kullanıcı standart bir listenin en altına kaydırdıktan sonra listenin sonuna yeni bir öğe eklenirse liste, kullanıcının mevcut öğe görünümünü korur. Örneğin, kullanıcı ekranın alt kısmındaki 10. öğeyi görüntülerken 11. öğe eklenirse görünüm 10. öğeye odaklanmaya devam eder ve 11. öğe, geçerli görünümün altında ekran dışında görünür.
Mesajlaşma uygulamaları veya canlı günlükler gibi kullanım alanlarında bu davranış genellikle istenmez. Yeni öğeler geldiğinde, listenin en altında olan kullanıcılar genellikle en son içeriği hemen görmek ister. Çok sayıda öğe aynı anda gelirse listede en son öğe en altta gösterilir (yani kullanıcı yukarı kaydırmadığı sürece bazı ara öğeler hiç gösterilmeyebilir).
Bu kullanım alanlarını desteklemek için TransformingLazyColumn, reverseLayout = true ayarını yaparak düzeni tersine çevirmenize olanak tanır. Bu işlem, listenin bağlantı noktasını üst kenardan alt kenara değiştirir.
Kolaylık sağlamak için reverseLayout = true ayarı, öğelerin görsel sırasını ve kaydırma hareketlerinin yönünü de tersine çevirir:
- Öğeler alttan üste doğru oluşturulur. Yani 0 dizini ekranın en altında görünür.
- Yukarı kaydırdığınızda dizinleri daha yüksek olan öğeler gösterilir.
Ters düzenle birlikte tutturup fırlatma davranışı eklemek için aşağıdaki snippet'te gösterildiği gibi flingBehavior ve rotaryScrollableBehavior öğelerini birleştirebilirsiniz:
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") } } } }
Aşağıdaki resimlerde normal liste ile ters liste arasındaki fark gösterilmektedir:
Listelerdeki kenar düğmeleri
Material 3'te, listelerin en altında kenarlara yaslanan bir düğme olan EdgeButton ekleyebilirsiniz. Ancak bunu TransformingLazyColumn içinde bir öğe olarak eklememeye dikkat edin. Bunun yerine ScreenScaffold içindeki edgeButton yuvasını kullanın.
edgeButton yuvasının kullanılması, düğmenin ekranın alt kısmında doğru şekilde konumlandırılmasını ve liste kaydırıldığında uygun şekilde davranmasını sağlar.
Aşağıdaki kod snippet'inde EdgeButton'nin nasıl uygulanacağı gösterilmektedir:
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, ) { // ... // ... } }
Listelerde SwipeToReveal
SwipeToReveal bileşeni, kaydırarak liste öğesiyle ilgili işlemlere (ör. Card veya Chip) erişmenizi sağlar. Kaydırma işlemi genellikle yandan bir veya iki işlem düğmesini (ör. "Sil" veya "Diğer") gösterir.
SwipeToReveal kodunu TransformingLazyColumn içinde kullanırken aşağıdaki yönergelere uyun:
- Kaydırma sırasında sıfırla: Kullanıcı listede kaydırdığında, kaydırılarak açılan öğeler kapalı durumlarına sıfırlanır.
- Tutarlı yükseklikler: Tutarlı bir görünüm sağlamak için işlem düğmesi yüksekliklerini, içteki kaydırılan öğeyle (
ButtonveyaCard) eşleşecek şekilde ayarlayın. - Kapsayıcıyı dönüştürme:
transformedHeightdeğiştiricisini vetransformationSpecdeğeriniSwipeToRevealbileşenine uygulayın. - Çift dönüştürme yapmayın: İçteki kaydırılan öğeye (
SwipeToRevealkapsayıcısının içindeki kart veya düğme)transformedHeightya datransformationdeğiştiricilerini uygulamayın.
Listelerde özel composable'lar
TransformingLazyColumn için özel yüzey bileşenleri oluştururken, composable'ınızın ekran kenarlarında sorunsuz bir şekilde ölçeklenmesi, solması ve dönüşmesi için aşağıdaki en iyi uygulamaları izleyin:
- Expose
SurfaceTransformation:CardveButtongibi standart Wear Compose Material 3 bileşenleriyle eşleşen, isteğe bağlı birSurfaceTransformationparametresini (varsayılan olaraknull) kabul edin. Bu, bileşenin bir liste dışında normal şekilde çalışmasına izin verirken arayanlarınTransformingLazyColumngeçmesineSurfaceTransformation(transformationSpec)olanak tanır. - Arama kodunda önce
Modifier.transformedHeightuygulayın: Özel composable'ınızıTransformingLazyColumniçine yerleştirirkenModifier.transformedHeight(this, transformationSpec)öğesini, arama kodunun değiştirici zincirindeki ilk değiştirici olarak iletin.SurfaceTransformationgörsel ölçeklendirme ve solma efektlerini uygularkentransformedHeight, liste düzenine öğenin yüksekliğini küçüldükçe yeniden hesaplamasını söylemek için kritik öneme sahiptir. - Dönüşüm katmanlarını, arayan
modifierve boyayıcıyı sırayla uygulayın:- Kapsayıcı dönüştürme katmanı: Hem arka planın hem de içeriğin ölçeklendirilmiş, eğilmiş koordinat alanında çizilmesi için kök kapsayıcının değiştirici zincirini
Modifier.graphicsLayerveapplyContainerTransformation()ile başlatın. - Arayan
modifier: Arayan tarafından iletilenmodifierparametresini (Modifier.transformedHeightdahil) önce, herhangi bir dahili boyutlandırma veya dolgudan önce uygulayın. - Dönüşüm olmadığında klibi şekillendirme:
transformationnullise arka planı çizmeden önceModifier.clip(shape)uygulayın.createContainerPainter()tarafından döndürülen boya, şekle göre kırpılır ancak düz bir boya kırpılmaz. Bu nedenle, bu olmadan arka plan, liste dışında kare köşelerle çizilir. - Dönüşen arka plan boyama:
Modifier.drawBehindvecreateContainerPainter()kullanılarak oluşturulan bir boyama aracıyla arka planı kapsayıcı katmanının içine çizin. - İçerik dönüştürme katmanı: İçerik çerçeveye yaklaştıkça daha erken solması için kapsayıcı şekle ikinci bir
Modifier.graphicsLayerileapplyContentTransformation()ve kırpma uygulayın.
- Kapsayıcı dönüştürme katmanı: Hem arka planın hem de içeriğin ölçeklendirilmiş, eğilmiş koordinat alanında çizilmesi için kök kapsayıcının değiştirici zincirini
Aşağıdaki snippet'te, bu dönüşümleri sırayla uygulayan özel bir BoardingPassCard composable'ın nasıl uygulanacağı gösterilmektedir:
@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 } }
Ardından, BoardingPassCard öğesini TransformingLazyColumn içinde kullanabilirsiniz. Bunun için Modifier.transformedHeight öğesini ilk değiştirici olarak SurfaceTransformation(transformationSpec) ile birlikte iletmeniz gerekir:
@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) ) } } } }
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir.
- Wear OS için Compose Codelab'i
- Listeler ve Izgaralar
- Compose'da Görünümleri Kullanma