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

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

API yüzeyi

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

  • state: Kaydırma öğesi üzerinde yapılan hesaplamalarla üretilen değeri depolamak için oluşturulan SwipeToDismissBoxState durumu. Bu durum, üretildiğinde 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ırarak güncelleme veya kapatma

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

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

  • Bileşen durumunu swipeToDismissBoxState yönetir. Öğeyle etkileşim tamamlandığında confirmValueChange geri çağırma işlevini tetikler. Geri çağırma gövdesi, farklı olası işlemleri işler. Geri çağırma, bileşene kapatma animasyonu gösterip göstermemesi gerektiğ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'yı çağırır. Bu, yapılacaklar öğesini güncellemeye karşılık gelir.
    • Öğe, sondan başa doğru kaydırılırsa geçerli todoItem değerini ileterek onRemove lambda'yı çağırır. Bu, yapılacaklar öğesini silmeye 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, "tamamlandı olarak işaretle" kaydırma işleminden sonra SwipeToDismissBox öğesinin hemen kaybolmasını önleyerek görsel bir onay veya animasyon gösterilmesine olanak tanır.
  • SwipeToDismissBox, her öğede yatay kaydırma etkileşimlerini etkinleştirir. Bekleme 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 görünür. 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 öğesinin üzerine çizilir. Bu durumda:
    • backgroundContent, arka plan rengi SwipeToDismissBoxValue'ye dayalı bir Icon olarak uygulanır:
    • Blue, StartToEnd kaydırıldığında yapılacaklar öğesini açıp kapatır.
    • Red, EndToStart kaydırıldığında yapılacaklar listesindeki bir öğeyi siliyor.
    • Settled için arka planda hiçbir şey gösterilmez. Öğe kaydırılmadığında arka planda hiçbir şey gösterilmez.
    • Benzer şekilde, gösterilen Icon kaydırma yönüne uyum sağlar:
    • StartToEnd, yapılacaklar listesindeki öğe tamamlandığında CheckBox simgesini, tamamlanmadığında ise CheckBoxOutlineBlank simgesini gösterir.
    • EndToStart, Delete simgesini 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 nesnelerini barındırabilen gözlemlenebilir bir liste oluşturur. Bu listeye bir öğe eklendiğinde veya listeden bir öğe kaldırıldığında Compose, kullanıcı arayüzünün bu listeye bağlı olan kısımlarını yeniden oluşturur.
    • mutableStateListOf() içinde, dört TodoItem nesnesi kendi açıklamalarıyla başlatılır: "Faturaları öde", "Market alışverişi yap", "Spor salonuna git" ve "Akşam yemeği ye".
  • LazyColumn, dikey olarak kaydırılan bir todoItems listesi gösterir.
  • onToggleDone = { todoItem -> ... }, kullanıcı bir nesneyi tamamlandı 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, yeniden oluşturmayı tetikleyerek kullanıcı arayüzünü günceller.
  • 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 de yeniden oluşturmaya neden olur ve öğe, görüntülenen listeden kaldırılır.
  • Öğe kapatıldığında değiştiricinin placementSpec işlevi çağrılacak şekilde her TodoListItem öğesine bir animateItem değiştirici uygulanır. Bu işlem, öğenin kaldırılmasını ve listedeki diğer öğelerin yeniden sıralanmasını animasyonlu olarak gösterir.

Sonuç

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

Şekil 1. Bir öğeyi tamamlandı olarak işaretleyebilen ve 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 düzey örnek: Kaydırma sırasında arka plan rengini canlandırma

Aşağıdaki snippet'lerde, kaydırma sırasında bir öğenin arka plan rengini canlandırmak 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 Icon composable'ının içeriğinin arkasındaki tuvale çizim yapar.
    • drawRect(), tuval üzerine bir dikdörtgen çizer ve çizim kapsamının tüm sınırlarını belirtilen Color ile doldurur.
  • Kaydırma sırasında öğenin arka plan rengi lerp kullanılarak sorunsuz bir şekilde geçiş yapar.
    • StartToEnd yönünden kaydırıldığında arka plan rengi kademeli olarak açık gri renkten maviye döner.
    • EndToStart tarafından kaydırıldığında arka plan rengi kademeli olarak açık griden kırmızıya değişir.
    • Bir renkten diğerine geçiş miktarı swipeToDismissBoxState.progress ile belirlenir.
  • OutlinedCard, liste öğeleri arasında hafif 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ümde yer alan ve aynı kod snippet'ini açıklayan Önemli noktalar bölümüne bakın.

Sonuç

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

Şekil 2. Animasyonlu arka plan renkleri ve işlem kaydedilmeden önce daha uzun bir eşik içeren, kaydırarak gösterme veya silme uygulaması.

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

Ek kaynaklar