Android 如何将布局修改器应用于Jetpack Compose中的每个可放置组件?
我的自定义布局中有一个可拖动的修改器。问题是,我的所有可放置对象都作为一个块移动,而我希望它们单独移动。正确的循环方式是什么,以确保一次只选择一个可放置项?还是有更好的方法?以下是我的自定义布局:Android 如何将布局修改器应用于Jetpack Compose中的每个可放置组件?,android,android-jetpack-compose,Android,Android Jetpack Compose,我的自定义布局中有一个可拖动的修改器。问题是,我的所有可放置对象都作为一个块移动,而我希望它们单独移动。正确的循环方式是什么,以确保一次只选择一个可放置项?还是有更好的方法?以下是我的自定义布局: @Composable fun CustomLayout( modifier: Modifier = Modifier, content: @Composable() () -> Unit ) { val coroutineScope = rememberCoro
@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
}
}
}
}
@Composable
趣味定制布局(
修饰符:修饰符=修饰符,
内容:@Composable()()->Unit
) {
val coroutineScope=rememberCoroutineScope()
val offsetX=记住{Animatable(0f)}
val offsetY=记住{Animatable(0f)}
布局(
修饰语=修饰语
.抵消{
抵消(
offsetX.value.roundToInt(),
offsetY.value.roundToInt()
)
}
.拖拉(
state=rememberdraggalestate{delta->
协同观测发射{
offsetX.snapTo(offsetX.value+delta)
}
},
方向=方向。水平,
onDragStarted={},
onDragStopped={
协同观测发射{
offsetX.animateTo(
targetValue=0f,
animationSpec=吐温(
持续时间毫秒=1000,
延迟毫秒=0
)
)
}
}
),
内容=内容
){可测量,约束->
val tileSize=constraints.maxWidth/7
val childConstraints=constraints.copy(
minWidth=minOf(constraints.minWidth,tileSize),
maxWidth=tileSize
)
val placeables=measureables.map{measured->
可测量。测量(儿童约束)
}
布局(constraints.maxWidth、constraints.maxHeight){
变量yPosition=0
val xPosition=0
placeables.foreachinedexed{index,placeable->
如果(index您的解决方案不起作用,因为您将偏移应用于整个布局,但需要将其应用于单个项目
Layout
仅用于布局项目:在MeasureScope
中,我们只能访问项目大小/位置,不能向其添加修饰符,因为这些修饰符将修改状态并导致递归
我的建议是将items count和item generator传递给您的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)
)
}
)