Kaydırma değiştiriciler

verticalScroll ve horizontalScroll değiştiricileri, içeriğinin sınırları maksimum boyut kısıtlamalarından daha büyük olduğunda kullanıcının bir öğeyi kaydırmasına izin vermenin en basit yolunu sunar. verticalScroll ve horizontalScroll değiştiricileriyle içerikleri çevirmeniz veya dengelemeniz gerekmez.

@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))
        }
    }
}

Kaydırma hareketlerine yanıt veren basit bir dikey liste
Şekil 1. Kaydırma hareketlerine yanıt veren basit bir dikey liste.

ScrollState, kaydırma konumunu değiştirmenize veya mevcut durumunu almanıza olanak tanır. Varsayılan parametrelerle oluşturmak için rememberScrollState() komutunu kullanın.

@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))
        }
    }
}

Kaydırılabilir alan değiştirici

scrollableArea değiştiricisi, özel kaydırılabilir kapsayıcılar oluşturmak için temel bir yapı taşıdır. scrollable değiştiricisi üzerinde daha üst düzey bir soyutlama sağlayarak hareket delta yorumlama, içerik kırpma ve kaydırma sonu efektleri gibi yaygın gereksinimleri karşılar.

scrollableArea özel uygulamalar için kullanılırken standart kaydırma listeleri için genellikle verticalScroll, horizontalScroll gibi hazır çözümleri veya LazyColumn gibi composable'ları tercih etmeniz gerekir. Bu üst düzey bileşenler, yaygın kullanım alanları için daha basittir ve scrollableArea kullanılarak oluşturulur.

scrollableArea ve scrollable değiştiricileri arasındaki fark

scrollableArea ile scrollable arasındaki temel fark, kullanıcı kaydırma hareketlerini nasıl yorumladıklarıdır:

  • scrollable (ham delta): Delta, kullanıcının ekrandaki girişinin (ör. işaretçi sürükleme) fiziksel hareketini doğrudan yansıtır.
  • scrollableArea (içerik odaklı delta): delta, kaydırma konumunda seçilen değişikliği temsil etmek için anlamsal olarak ters çevrilir. Böylece içerik, kullanıcının hareketiyle birlikte hareket ediyormuş gibi görünür. Bu hareket genellikle işaretçi hareketinin tersidir.

Şöyle düşünebilirsiniz: scrollable, işaretçinin nasıl hareket ettiğini belirtirken scrollableArea, bu işaretçi hareketini içeriğin tipik bir kaydırılabilir görünümde nasıl hareket etmesi gerektiğine dönüştürür. Bu tersine çevirme, standart bir kaydırılabilir kapsayıcı uygularken scrollableArea öğesinin daha doğal hissettirmesinin nedenidir.

Aşağıdaki tabloda, yaygın senaryolar için fark işaretleri özetlenmiştir:

Kullanıcı hareketi

scrollable tarafından dispatchRawDelta için bildirilen fark

scrollableArea tarafından dispatchRawDelta için bildirilen fark*

İşaretçi YUKARI hareket eder

Negatif

Positive

İşaretçi AŞAĞI hareket eder.

Positive

Negatif

İşaretçi SOLA hareket eder.

Negatif

Pozitif (RTL için negatif)

İşaretçi SAĞA hareket eder.

Positive

Negatif (RTL için pozitif)

(*) scrollableArea delta işaretiyle ilgili not: scrollableArea delta işareti, basit bir ters çevirme işleminden ibaret değildir. Bu özellik, aşağıdaki faktörleri akıllıca değerlendirir:

  1. Yön: Dikey veya yatay.
  2. LayoutDirection: Soldan sağa veya sağdan sola (özellikle yatay kaydırma için önemlidir).
  3. reverseScrolling işareti: Kaydırma yönünün ters çevrilip çevrilmediğini belirtir.

scrollableArea, kaydırma deltasını tersine çevirmenin yanı sıra içeriği düzenin sınırlarına göre kırpar ve kaydırma efektlerinin oluşturulmasını yönetir. Varsayılan olarak LocalOverscrollFactory tarafından sağlanan efekti kullanır. OverscrollEffect parametresini kabul eden scrollableArea aşırı yüklemesini kullanarak bunu özelleştirebilir veya devre dışı bırakabilirsiniz.

scrollableArea değiştiricisi ne zaman kullanılır?

horizontalScroll veya verticalScroll değiştiricileri ya da Lazy düzenleri tarafından yeterince desteklenmeyen özel bir kaydırma bileşeni oluşturmanız gerektiğinde scrollableArea değiştiricisini kullanmanız gerekir. Bu durum genellikle şu tür vakalarda görülür:

  • Özel düzen mantığı: Öğelerin düzeni, kaydırma konumuna göre dinamik olarak değiştiğinde.
  • Benzersiz görsel efektler: Çocuklar sayfayı kaydırırken dönüşümler, ölçeklendirme veya diğer efektler uygulama.
  • Doğrudan kontrol: verticalScroll veya Lazy düzenlerinin sunduklarının ötesinde, kaydırma mekanizmaları üzerinde ayrıntılı kontrole ihtiyaç duyma.

scrollableArea kullanarak özel çark listeleri oluşturun

Aşağıdaki örnekte, öğelerin merkezden uzaklaştıkça küçülerek "tekerlek benzeri" bir görsel efekt oluşturduğu özel bir dikey liste oluşturmak için scrollableArea kullanımı gösterilmektedir. Kaydırmaya bağlı bu tür dönüşümler, scrollableArea için mükemmel bir kullanım alanıdır.

Şekil 2. scrollableArea kullanılarak özelleştirilmiş dikey liste.

@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
            }
        }
    }
}
// ...

Kaydırılabilir değiştirici

scrollable değiştiricisi, kaydırma değiştiricilerinden farklıdır. scrollable, kaydırma hareketlerini algılar ve deltaları yakalar ancak içeriğini otomatik olarak dengelemez. Bunun yerine, bu değiştiricinin doğru çalışması için gereken ScrollableState aracılığıyla kullanıcıya yetki verilir.

ScrollableState oluştururken her kaydırma adımında (hareket girişi, kolay kaydırma veya kaydırma hareketiyle) piksel cinsinden delta ile çağrılacak bir consumeScrollDelta işlevi sağlamanız gerekir. Bu işlev, scrollable değiştiricisine sahip iç içe yerleştirilmiş öğelerin bulunduğu durumlarda etkinliğin doğru şekilde yayılmasını sağlamak için kullanılan kaydırma mesafesi miktarını döndürmelidir.

Aşağıdaki snippet, hareketleri algılar ve bir ofset için sayısal değer gösterir ancak hiçbir öğeyi ofsetlemez:

@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())
    }
}

Parmakla basma işlemini algılayan ve parmağın konumunun sayısal değerini gösteren bir kullanıcı arayüzü öğesi
Şekil 3. Parmakla basma işlemini algılayan ve parmağın konumunun sayısal değerini gösteren bir kullanıcı arayüzü öğesi.