簡體   English   中英

使用 animation 在 LazyColumn 內 SwipeToDismiss

[英]SwipeToDismiss inside LazyColumn with animation

我正在嘗試使用 Jetpack Compose 來實現類似的目標 換句話說,像我們可以在RecyclerView中使用ItemTouchHelperclass DiffCallBack: DiffUtil.ItemCallback<RvModel>()一樣滑動刪除,我們可以看到enter - exit animations ,然后列表優雅地向上或向下移動項目已插入或刪除。

這是我嘗試過的:

LazyColumn(state = listState) {
    items(products, {listItem:InventoryEntity -> listItem.inventoryId}) { item ->
        var unread by remember { mutableStateOf(false) }
        val dismissState = rememberDismissState(
            confirmStateChange = {
                if (it == DismissValue.DismissedToEnd) unread = !unread
                it != DismissValue.DismissedToEnd
            }
        )
        val isDismissed = dismissState.isDismissed(DismissDirection.EndToStart)

        if (dismissState.isDismissed(DismissDirection.EndToStart)){
            LaunchedEffect(Unit) {
                delay(300)
                viewModel.deleteProduct(item.inventoryId)
            }

        }

        var itemAppeared by remember { mutableStateOf(!columnAppeared) }
        LaunchedEffect(Unit) {
            itemAppeared = true
        }

        AnimatedVisibility(
            visible = itemAppeared && !isDismissed,
            exit = shrinkVertically(
                animationSpec = tween(
                    durationMillis = 300,
                )
            ),
            enter = expandVertically(
                animationSpec = tween(
                    durationMillis = 300
                )
            )
        ) {
            SwipeToDismiss(
                state = dismissState,
                modifier = Modifier.padding(vertical = 4.dp),
                directions = setOf(
                    DismissDirection.StartToEnd,
                    DismissDirection.EndToStart
                ),
                dismissThresholds = { direction ->
                    FractionalThreshold(if (direction == DismissDirection.StartToEnd) 0.25f else 0.5f)
                },
                background = {
                    val direction =
                        dismissState.dismissDirection ?: return@SwipeToDismiss
                    val color by animateColorAsState(
                        when (dismissState.targetValue) {
                            DismissValue.Default -> Color.LightGray
                            DismissValue.DismissedToEnd -> Color.Green
                            DismissValue.DismissedToStart -> Color.Red
                        }
                    )
                    val alignment = when (direction) {
                        DismissDirection.StartToEnd -> Alignment.CenterStart
                        DismissDirection.EndToStart -> Alignment.CenterEnd
                    }
                    val icon = when (direction) {
                        DismissDirection.StartToEnd -> Icons.Default.Done
                        DismissDirection.EndToStart -> Icons.Default.Delete
                    }
                    val scale by animateFloatAsState(
                        if (dismissState.targetValue == DismissValue.Default) 0.75f else 1f
                    )

                    Box(
                        Modifier
                            .fillMaxSize()
                            .background(color)
                            .padding(horizontal = 20.dp),
                        contentAlignment = alignment
                    ) {
                        Icon(
                            icon,
                            contentDescription = "Localized description",
                            modifier = Modifier.scale(scale)
                        )
                    }
                },
                dismissContent = {
                    Card(
                        elevation = animateDpAsState(
                            if (dismissState.dismissDirection != null) 4.dp else 0.dp
                        ).value
                    ) {
                        ProductRow(product = item, number = item.inventoryId)
                    }
                }
            )
        }
    }
}

即使它有效。 滾動不流暢,當我向上滾動時,它會跳到頂部。 實現這個 function 的正確方法是什么?

上周 google 宣布了 compose Version 1.1.0-beta03 現在我們有了一種新的方式來為項目設置動畫。 他們引入了一個新的修飾符: Modifier.animateItemPlacement() 您可以在此鏈接中找到最新的 compose 版本。

我將嘗試使用最少的代碼發布一個示例,以便您可以重現它並查看如何使用 animation 在 LazyColumn 內實現 SwipeToDismiss。

數據 Class 存儲信息:

data class DataSet(
    val itemId: Int,
    val itemName: String,
    val itemQty: String
)

比較器來比較列表項:

private val ListComparator = Comparator<DataSet> { left, right ->
    left.itemId.compareTo(right.itemId)
}

我們每個項目的行:

@Composable
fun ItemRow(
    modifier: Modifier = Modifier,
    product: DataSet,
    number: Int
) {

    Card(
        shape = RoundedCornerShape(4.dp),
        modifier = modifier
            .padding(8.dp)
            .fillMaxWidth(),
        backgroundColor = Color.LightGray
    ) {
        Row(modifier = modifier) {
            Text(
                text = "$number.", modifier = Modifier
                    .weight(2f)
                    .padding(start = 8.dp, end = 4.dp)
            )
            Text(
                text = product.itemName, modifier = Modifier
                    .weight(10f)
                    .padding(end = 4.dp)
            )
            Text(
                text = product.itemQty, modifier = Modifier
                    .weight(2f)
                    .padding(end = 4.dp)
            )
        }
    }
}

將所有內容放在我們的可組合項中:

@ExperimentalMaterialApi
@ExperimentalFoundationApi
@Composable
fun helloWorld() {
    var list by remember { mutableStateOf(listOf<DataSet>()) }

    val comparator by remember { mutableStateOf(ListComparator) }

    LazyColumn {
        item {
            Button(onClick = {
                list = list + listOf(DataSet((0..1111).random(), "A random item", "100"))
            }) {
                Text("Add an item to the list")
            }
        }

        val sortedList = list.sortedWith(comparator)

        items(sortedList, key = { it.itemId }) { item ->
            val dismissState = rememberDismissState()
            if (dismissState.isDismissed(DismissDirection.EndToStart)) {
                list = list.toMutableList().also { it.remove(item) } // remove
            }
            SwipeToDismiss(
                state = dismissState,
                modifier = Modifier
                    .padding(vertical = 1.dp)
                    .animateItemPlacement(),
                directions = setOf(DismissDirection.StartToEnd, DismissDirection.EndToStart),
                dismissThresholds = { direction ->
                    FractionalThreshold(if (direction == DismissDirection.StartToEnd) 0.25f else 0.5f)
                },
                background = {
                    val direction = dismissState.dismissDirection ?: return@SwipeToDismiss
                    val color by animateColorAsState(
                        when (dismissState.targetValue) {
                            DismissValue.Default -> Color.LightGray
                            DismissValue.DismissedToEnd -> Color.Green
                            DismissValue.DismissedToStart -> Color.Red
                        }
                    )
                    val alignment = when (direction) {
                        DismissDirection.StartToEnd -> Alignment.CenterStart
                        DismissDirection.EndToStart -> Alignment.CenterEnd
                    }
                    val icon = when (direction) {
                        DismissDirection.StartToEnd -> Icons.Default.Done
                        DismissDirection.EndToStart -> Icons.Default.Delete
                    }
                    val scale by animateFloatAsState(
                        if (dismissState.targetValue == DismissValue.Default) 0.75f else 1f
                    )

                    Box(
                        Modifier
                            .fillMaxSize()
                            .background(color)
                            .padding(horizontal = 20.dp),
                        contentAlignment = alignment
                    ) {
                        Icon(
                            icon,
                            contentDescription = "Localized description",
                            modifier = Modifier.scale(scale)
                        )
                    }
                },
                dismissContent = {
                    Card(
                        elevation = animateDpAsState(
                            if (dismissState.dismissDirection != null) 4.dp else 0.dp
                        ).value
                    ) {
                        ItemRow(
                            product = item,
                            number = item.itemId
                        )
                    }
                }
            )
        }
    }
}

作為參考並查看有關如何使用Modifier.animateItemPlacement()的其他方法,您可以查看 Google 發布的此示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM