Reddetmek veya güncellemek için kaydırın

SwipeToDismissBox bileşeni, kullanıcının bir öğeyi sola veya sağa kaydırarak reddetmesine ya da güncellemesine olanak tanır.

API yüzeyi

Kaydırma hareketleriyle tetiklenen işlemleri uygulamak için SwipeToDismissBox bileşenini kullanın. Temel parametreler şunlardır:

  • state: Kaydırma öğesindeki hesaplamalar tarafından üretilen değeri depolamak için oluşturulan SwipeToDismissBoxState durumu. Bu değer oluşturulduğunda etkinlikleri tetikler.
  • backgroundContent: Öğe içeriğinin arkasında gösterilen ve içerik kaydırıldığında ortaya çıkan özelleştirilebilir bir composable.

Temel örnek: Kaydırmayla güncelleme veya reddetmek

Bu örnekteki snippet'ler, başlangıçtan sona doğru kaydırıldığında öğeyi güncelleyen veya sondan başa doğru kaydırıldığında öğeyi kapatan bir kaydırma uygulaması göstermektedir.

data class TodoItem(
    val itemDescription: String,
    var isItemDone: Boolean = false
)

@Composable
fun TodoListItem(
    todoItem: TodoItem,
    onToggleDone: (TodoItem) -> Unit,
    onRemove: (TodoItem) -> Unit,
    modifier: Modifier = Modifier,
) {
    val swipeToDismissBoxState = rememberSwipeToDismissBoxState(
        confirmValueChange = {
            if (it == StartToEnd) onToggleDone(todoItem)
            else if (it == EndToStart) onRemove(todoItem)
            // Reset item when toggling done status
            it != StartToEnd
        }
    )

    SwipeToDismissBox(
        state = swipeToDismissBoxState,
        modifier = modifier.fillMaxSize(),
        backgroundContent = {
            when (swipeToDismissBoxState.dismissDirection) {
                StartToEnd -> {
                    Icon(
                        if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank,
                        contentDescription = if (todoItem.isItemDone) "Done" else "Not done",
                        modifier = Modifier
                            .fillMaxSize()
                            .background(Color.Blue)
                            .wrapContentSize(Alignment.CenterStart)
                            .padding(12.dp),
                        tint = Color.White
                    )
                }
                EndToStart -> {
                    Icon(
                        imageVector = Icons.Default.Delete,
                        contentDescription = "Remove item",
                        modifier = Modifier
                            .fillMaxSize()
                            .background(Color.Red)
                            .wrapContentSize(Alignment.CenterEnd)
                            .padding(12.dp),
                        tint = Color.White
                    )
                }
                Settled -> {}
            }
        }
    ) {
        ListItem(
            headlineContent = { Text(todoItem.itemDescription) },
            supportingContent = { Text("swipe me to update or remove.") }
        )
    }
}

Kodla ilgili önemli noktalar

  • swipeToDismissBoxState, bileşen durumunu yönetir. Öğeyle etkileşim sona erdiğinde confirmValueChange geri çağırma işlevini tetikler. Geri çağırma gövdesi, olası farklı işlemleri yönetir. Geri çağırma işlevi, bileşene kapatma animasyonu gösterip göstermeyeceğini belirten bir boole değeri döndürür. Bu durumda:
    • Öğe baştan sona kaydırılırsa geçerli todoItem değerini ileterek onToggleDone lambda işlevini çağırır. Bu, yapılacaklar öğesinin güncellenmesine karşılık gelir.
    • Öğe uçtan uca kaydırılırsa mevcut todoItem değerini ileterek onRemove lambda işlevini çağırır. Bu işlem, yapılacaklar listesindeki öğenin silinmesine karşılık gelir.
    • it != StartToEnd: Bu satır, kaydırma yönü StartToEnd değilse true, aksi takdirde false değerini döndürür. false döndürmek, "açma/kapatma işlemi tamamlandı" kaydırma işleminden sonra SwipeToDismissBox'ın hemen kaybolmasını önler ve görsel bir onay veya animasyon sağlar.
  • SwipeToDismissBox, her öğede yatay kaydırma etkileşimlerini etkinleştirir. Dinlenme durumunda, bileşenin iç içeriğini gösterir ancak kullanıcı kaydırmaya başladığında içerik kaldırılır ve backgroundContent simgesi gösterilir. Hem normal içerik hem de backgroundContent, kendilerini oluşturmak için üst kapsayıcının tüm kısıtlamalarını alır. content, backgroundContent'un üzerine çizilir. Bu durumda:
    • backgroundContent, SwipeToDismissBoxValue'ye dayalı bir arka plan rengine sahip Icon olarak uygulanır:
    • Blue StartToEnd kaydırırken: yapılacaklar listesindeki bir öğeyi etkinleştirme veya devre dışı bırakma.
    • Red EndToStart kaydırırken: yapılacaklar listesindeki bir öğeyi silme.
    • Settled için arka planda hiçbir şey gösterilmez. Öğe kaydırıldığında arka planda hiçbir şey gösterilmez.
    • Benzer şekilde, gösterilen Icon, kaydırma yönüne uyar:
    • StartToEnd, yapılacaklar listesindeki öğe tamamlandığında CheckBox simgesi, tamamlanmadığında ise CheckBoxOutlineBlank simgesi gösterir.
    • EndToStart, Delete simgesi gösterir.

@Composable
private fun SwipeItemExample() {
    val todoItems = remember {
        mutableStateListOf(
            TodoItem("Pay bills"), TodoItem("Buy groceries"),
            TodoItem("Go to gym"), TodoItem("Get dinner")
        )
    }

    LazyColumn {
        items(
            items = todoItems,
            key = { it.itemDescription }
        ) { todoItem ->
            TodoListItem(
                todoItem = todoItem,
                onToggleDone = { todoItem ->
                    todoItem.isItemDone = !todoItem.isItemDone
                },
                onRemove = { todoItem ->
                    todoItems -= todoItem
                },
                modifier = Modifier.animateItem()
            )
        }
    }
}

Kodla ilgili önemli noktalar

  • mutableStateListOf(...), TodoItem nesnesi barındırabilen gözlemlenebilir bir liste oluşturur. Bu listeye bir öğe eklendiğinde veya listeden kaldırıldığında, Oluştur, kullanıcı arayüzünün bu öğeye bağlı olan bölümlerini yeniden oluşturur.
    • mutableStateListOf() içinde, dört TodoItem nesnesi ilgili açıklamalarıyla başlatılır: "Faturaları öde", "Alışveriş yap", "Spor salonuna git" ve "Akşam yemeği ye".
  • LazyColumn, todoItems öğelerinin dikey olarak kaydırılan bir listesini görüntüler.
  • onToggleDone = { todoItem -> ... }, kullanıcı bir nesneyi bitti olarak işaretlediğinde TodoListItem içinden çağrılan bir geri çağırma işlevidir. todoItem öğesinin isItemDone özelliğini günceller. todoItems bir mutableStateListOf olduğundan bu değişiklik, kullanıcı arayüzünü güncelleyerek yeniden birleştirme işlemini tetikler.
  • onRemove = { todoItem -> ... }, kullanıcı öğeyi kaldırdığında tetiklenen bir geri çağırma işlevidir. Belirli bir todoItem öğesini todoItems listesinden kaldırır. Bu işlem, yeniden derlemeye de neden olur ve öğe, görüntülenen listeden kaldırılır.
  • Her TodoListItem öğesine bir animateItem değiştirici uygulanır. Böylece, öğe kapatıldığında değiştiricinin placementSpec işlevi çağrılır. Bu işlem, öğenin kaldırılmasının yanı sıra listedeki diğer öğelerin yeniden sıralanmasını animasyonlu olarak gösterir.

Sonuç

Aşağıdaki videoda, önceki snippet'lerdeki temel kaydırarak kapatma işlevi gösterilmektedir:

Şekil 1. Hem bir öğeyi tamamlandı olarak işaretleyebilen hem de listedeki bir öğe için kapatma animasyonu gösterebilen, kaydırarak kapatma özelliğinin temel bir uygulaması.

Örnek kodun tamamı için GitHub kaynak dosyasına bakın.

İleri seviye örnek: Kaydırma sırasında arka plan renginin animasyonu

Aşağıdaki snippet'lerde, öğenin arka plan renginin kaydırıldığında animasyonlu olarak gösterilmesi için konumsal eşiğin nasıl dahil edileceği gösterilmektedir.

data class TodoItem(
    val itemDescription: String,
    var isItemDone: Boolean = false
)

@Composable
fun TodoListItemWithAnimation(
    todoItem: TodoItem,
    onToggleDone: (TodoItem) -> Unit,
    onRemove: (TodoItem) -> Unit,
    modifier: Modifier = Modifier,
) {
    val swipeToDismissBoxState = rememberSwipeToDismissBoxState(
        confirmValueChange = {
            if (it == StartToEnd) onToggleDone(todoItem)
            else if (it == EndToStart) onRemove(todoItem)
            // Reset item when toggling done status
            it != StartToEnd
        }
    )

    SwipeToDismissBox(
        state = swipeToDismissBoxState,
        modifier = modifier.fillMaxSize(),
        backgroundContent = {
            when (swipeToDismissBoxState.dismissDirection) {
                StartToEnd -> {
                    Icon(
                        if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank,
                        contentDescription = if (todoItem.isItemDone) "Done" else "Not done",
                        modifier = Modifier
                            .fillMaxSize()
                            .drawBehind {
                                drawRect(lerp(Color.LightGray, Color.Blue, swipeToDismissBoxState.progress))
                            }
                            .wrapContentSize(Alignment.CenterStart)
                            .padding(12.dp),
                        tint = Color.White
                    )
                }
                EndToStart -> {
                    Icon(
                        imageVector = Icons.Default.Delete,
                        contentDescription = "Remove item",
                        modifier = Modifier
                            .fillMaxSize()
                            .background(lerp(Color.LightGray, Color.Red, swipeToDismissBoxState.progress))
                            .wrapContentSize(Alignment.CenterEnd)
                            .padding(12.dp),
                        tint = Color.White
                    )
                }
                Settled -> {}
            }
        }
    ) {
        OutlinedCard(shape = RectangleShape) {
            ListItem(
                headlineContent = { Text(todoItem.itemDescription) },
                supportingContent = { Text("swipe me to update or remove.") }
            )
        }
    }
}

Kodla ilgili önemli noktalar

  • drawBehind, doğrudan Iconkompozitinin içeriğinin arkasındaki tuvale çizer.
    • drawRect(), tuval üzerine bir dikdörtgen çizer ve çizim kapsamının tüm sınırlarını belirtilen Color ile doldurur.
  • Kaydırırken öğenin arka plan rengi lerp kullanılarak sorunsuz bir şekilde geçiş yapar.
    • StartToEnd'ten kaydırıldığında arka plan rengi açık griden maviye kademeli olarak değişir.
    • EndToStart'ten kaydırıldığında arka plan rengi açık griden kırmızıya kademeli olarak değişir.
    • Bir renkten diğerine geçiş miktarı swipeToDismissBoxState.progress tarafından belirlenir.
  • OutlinedCard, liste öğeleri arasına ince bir görsel ayrım ekler.

@Composable
private fun SwipeItemWithAnimationExample() {
    val todoItems = remember {
        mutableStateListOf(
            TodoItem("Pay bills"), TodoItem("Buy groceries"),
            TodoItem("Go to gym"), TodoItem("Get dinner")
        )
    }

    LazyColumn {
        items(
            items = todoItems,
            key = { it.itemDescription }
        ) { todoItem ->
            TodoListItemWithAnimation(
                todoItem = todoItem,
                onToggleDone = { todoItem ->
                    todoItem.isItemDone = !todoItem.isItemDone
                },
                onRemove = { todoItem ->
                    todoItems -= todoItem
                },
                modifier = Modifier.animateItem()
            )
        }
    }
}

Kodla ilgili önemli noktalar

  • Bu kodla ilgili önemli noktalar için önceki bir bölümdeki Önemli noktalar'a bakın. Bu bölümde, aynı kod snippet'i açıklanmaktadır.

Sonuç

Aşağıdaki videoda, animasyonlu arka plan rengiyle gelişmiş işlevler gösterilmektedir:

Şekil 2. Animasyonlu arka plan renkleri ve işlemin kaydedilmesinden önce daha uzun bir eşikle göstermek veya silmek için kaydırma özelliğinin uygulanması.

Örnek kodun tamamı için GitHub kaynak dosyasına bakın.

Ek kaynaklar