在LazyColumn中使用动画进行SwipeToDismisse

SwipeToDismiss inside LazyColumn with animation(在LazyColumn中使用动画进行SwipeToDismisse)
本文介绍了在LazyColumn中使用动画进行SwipeToDismisse的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现类似this的内容,但使用Jetpack Compose。换句话说,像我们在RecyclerViewItemTouchHelperclass 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)
                    }
                }
            )
        }
    }
}

即使它有效。滚动并不流畅,当我向上滚动时,它会跳到顶部。实现此功能的正确方式是什么?

推荐答案

最近谷歌宣布发布ComposeVersion 1.1.0-beta03。现在我们有了一种新的方法来制作物品的动画。他们引入了一个新的修饰语:Modifier.animateItemPlacement()。您可以在this link中找到最新的撰写版本。

我将尝试用最少的代码发布一个示例,以便您可以重现它,并了解如何使用动画在LazyColumn中实现SwipeToDismisse。

存储信息的数据类:

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发布的this example。

这篇关于在LazyColumn中使用动画进行SwipeToDismisse的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

How to target newer versions in .gitlab-ci.yml using auto devops (java 11 instead of 8 and Android 31 instead of 29)(如何在.gitlab-ci.yml中使用自动开发工具(Java 11而不是8,Android 31而不是29)瞄准较新的版本)
Android + coreLibraryDesugaring: which Java 11 APIs can I expect to work?(Android+core LibraryDesugering:我可以期待哪些Java 11API能够工作?)
How to render something in an if statement React Native(如何在If语句中呈现某些内容Reaction Native)
How can I sync two flatList scroll position in react native(如何在本机Reaction中同步两个平面列表滚动位置)
Using Firebase Firestore in offline only mode(在仅脱机模式下使用Firebase FiRestore)
Crash on Google Play Pre-Launch Report: java.lang.NoSuchMethodError(Google Play发布前崩溃报告:java.lang.NoSuchMethodError)