如何在 Jetpack Compose 中将布局修改器单独应用于每个可放置元素?
2021-05-09
720
我的自定义布局中有一个可拖动修饰符。问题是,我的所有可放置物都作为一个块移动,而我希望它们单独移动。循环遍历它们的正确方法是什么,以确保一次只选择一个可放置物?或者有更好的方法吗?这是我的自定义布局:
@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
}
}
}
}
在这里,我希望一次只移动一个图块:
1个回答
您的解决方案不起作用,因为您将偏移量应用于整个布局,但您需要将其应用于单个项目。
Layout
仅用于布局项目:在
MeasureScope
中,我们只能访问项目大小/位置,并且我们无法向它们添加修饰符,因为这些修饰符会修改状态并导致递归。
我的建议是将项目计数和项目生成器传递给您的 Composable,这样我们就可以向每个项目添加偏移量和可拖动修饰符:
@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)
)
}
)
Phil Dukhov
2021-05-10