android - 如何在 Jetpack Compose 中将布局修改器单独应用于每个可放置项?

标签 android android-jetpack-compose

我的自定义布局中有一个可拖动修饰符。问题是我的所有可放置物都作为一个 block 移动,而我希望它们单独移动。循环遍历它们以确保一次仅选择一个可放置项的正确方法是什么?或者有更好的方法吗?这是我的自定义布局:

    @Composable
fun CustomLayout(
    modifier: Modifier = Modifier,
    content: @Composable() () -> Unit
) {
    val coroutineScope = rememberCoroutineScope()
    val offsetX = remember { Animatable(0f) }
    val offsetY = remember { Animatable(0f) }

    Layout(
        modifier = modifier
            .offset {
                IntOffset(
                    offsetX.value.roundToInt(),
                    offsetY.value.roundToInt()
                )
            }
            .draggable(
                state = rememberDraggableState { delta ->
                    coroutineScope.launch {
                        offsetX.snapTo(offsetX.value + delta)
                    }
                },
                orientation = Orientation.Horizontal,
                onDragStarted = {},
                onDragStopped = {

                    coroutineScope.launch {

                        offsetX.animateTo(
                            targetValue = 0f,
                            animationSpec = tween(
                                durationMillis = 1000,
                                delayMillis = 0
                            )
                        )
                    }
                }
            ),
        content = content
    ) { measurables, constraints ->
        val tileSize = constraints.maxWidth / 7
        val childConstraints = constraints.copy(
            minWidth = minOf(constraints.minWidth, tileSize),
            maxWidth = tileSize
        )
        val placeables = measurables.map { measurable ->
            measurable.measure(childConstraints)
        }

        layout(constraints.maxWidth, constraints.maxHeight) {
            var yPosition = 0
            val xPosition = 0
            placeables.forEachIndexed { index, placeable ->
                if (index <= 6) {
                    placeable.placeRelative(x = xPosition, y = yPosition)
                } else {
                    placeable.placeRelative(
                        constraints.maxWidth - tileSize,
                        yPosition - placeable.height * 7
                    )
                }
                yPosition += placeable.height
            }
        }
    }
}

在这里,我想一次只移动一个图 block :

enter image description here

最佳答案

您的解决方案不起作用,因为您将偏移量应用于整个布局,但您需要将其应用于单个项目。

Layout 仅用于布局项目:在 MeasureScope 中,我们只能访问项目大小/位置,并且无法向它们添加修饰符,因为它们会修改状态会导致递归。

我的建议是将项目计数和项目生成器传递给您的可组合项,这样我们就可以向每个项目添加偏移和可拖动修饰符:

@Composable
fun DraggableLayout(
    modifier: Modifier = Modifier,
    count: Int,
    item: @Composable (Int, Modifier) -> Unit
) {
    val coroutineScope = rememberCoroutineScope()
    val offsetsX = remember { mutableStateMapOf<Int, Animatable<Float, AnimationVector1D>>() }
    CustomLayout(
        modifier = modifier,
        content = {
            for (i in 0 until count) {
                item(
                    i,
                    Modifier
                        .offset {
                            IntOffset(
                                offsetsX[i]?.value?.roundToInt() ?: 0,
                                0
                            )
                        }
                        .draggable(
                            state = rememberDraggableState { delta ->
                                coroutineScope.launch {
                                    val offsetX = offsetsX[i] ?: Animatable(0f)
                                    offsetX.snapTo(offsetX.value + delta)
                                    offsetsX[i] = offsetX
                                }
                            },
                            orientation = Orientation.Horizontal,
                            onDragStarted = {},
                            onDragStopped = {
                                coroutineScope.launch {
                                    offsetsX[i]!!.animateTo(
                                        targetValue = 0f,
                                        animationSpec = tween(
                                            durationMillis = 1000,
                                            delayMillis = 0
                                        )
                                    )
                                }
                            }
                        ),
                )
            }
        }
    )
}

@Composable
fun CustomLayout(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content,
    ) { measurables, constraints ->
        val tileSize = constraints.maxWidth / 7
        val childConstraints = constraints.copy(
            minWidth = minOf(constraints.minWidth, tileSize),
            maxWidth = tileSize
        )
        val placeables = measurables.map { measurable ->
            measurable.measure(childConstraints)
        }

        layout(constraints.maxWidth, constraints.maxHeight) {
            var yPosition = 0
            val xPosition = 0
            placeables.forEachIndexed { index, placeable ->
                if (index <= 6) {
                    placeable.placeRelative(x = xPosition, y = yPosition)
                } else {
                    placeable.placeRelative(
                        constraints.maxWidth - tileSize,
                        yPosition - placeable.height * 7
                    )
                }
                yPosition += placeable.height
            }
        }
    }
}

并像这样使用它:

CustomLayout(
    count = 10,
    item = { i, modifier ->
        Text(
            "Test $i",
            modifier = Modifier
                .size(50.dp)
                .then(modifier)
        )
    }
)

结果: enter image description here

关于android - 如何在 Jetpack Compose 中将布局修改器单独应用于每个可放置项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67457124/

相关文章:

android - 自动后台通知firebase数据库

android - Kamailio 和安卓 SIP

android - 如何完成除主 Activity 之外的所有 Activity 并调用另一个 Activity

android - 如何在 Jetpack Compose 中移动 slider 时消除拖动效果

android - 如何更改 android compose TextField 的内容填充?

android - 首选项菜单中 Android 向上/向后导航的动态父 Activity

android - 渐变不适用于 kitkat 设备 android

android - 如何在撰写中将文本字段的值分配给 hoistedState ?

android - Jetpack 撰写 : What is the best way to support all screen sizes?

android - 如何将 id 和应用程序传递给 Jetpack Compose 中的 viewModel/viewModelFactory?