我是 Jetpack Compose 的新手,我正在尝试进行拖放屏幕,将项目从一列移动到另一列。我从this链接中获得灵感,并创建了以下文件:
任务列.kt
@Preview
@Composable
fun TaskColumns() {
var columnWidth by remember {
mutableStateOf(0.dp)
}
val density = LocalDensity.current
val items = remember {
mutableListOf(
mutableListOf(5,6,7,8),
mutableListOf(),
mutableListOf(),
mutableListOf())
}
Surface(
Modifier.fillMaxSize()
) {
LongPressDraggable {
Row(Modifier.padding(4.dp)) {
repeat(4){
val column = it
DropTarget<IntArray>(modifier = Modifier.weight(1f)) { a, data ->
val n = data?.get(0)
val i = data?.get(1)
val c = data?.get(2)
var color = if (a) Color.Green
else Color.Blue
if (i != null && n != null && c != null) {
if (c != column){
Log.d("DND", "${data[0]}, ${data[1]}")
items[column].add(n)
items[c].remove(n)
}
color = Color.Blue
}
Column(
Modifier
.fillMaxHeight()
.fillMaxWidth()
.padding(4.dp)
.background(color)
.onPlaced {
columnWidth = with(density) { it.size.width.toDp() }
}
) {
items[column].forEachIndexed { index, item ->
DragTarget(
modifier = Modifier,
dataToDrop = intArrayOf(item, index, column),
onDragCustomAction = {
Log.d("DND", "$item")
}
) {
Column(
Modifier
.size(columnWidth)
.aspectRatio(1f / 1f)
.background(Color.Black),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "$item", color = Color.White)
}
}
Spacer(modifier = Modifier.height(8.dp))
}
}
}
}
}
}
}
}
拖放.kt
internal val LocalDragTargetInfo = compositionLocalOf { DragTargetInfo() }
@Composable
fun LongPressDraggable(
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit
) {
val state = remember { DragTargetInfo() }
CompositionLocalProvider(
LocalDragTargetInfo provides state
) {
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.TopStart)
{
content()
if (state.isDragging) {
var targetSize by remember {
mutableStateOf(IntSize.Zero)
}
Box(modifier = Modifier
.graphicsLayer {
val offset = (state.dragPosition + state.dragOffset)
// scaleX = 1.3f
// scaleY = 1.3f
alpha = if (targetSize == IntSize.Zero) 0f else .9f
translationX = offset.x.minus(targetSize.width / 2)
translationY = offset.y.minus(targetSize.height / 2)
}
.onGloballyPositioned {
targetSize = it.size
}
) {
state.draggableComposable?.invoke()
}
}
}
}
}
@Composable
fun <T> DragTarget(
modifier: Modifier,
dataToDrop: T,
onDragCustomAction: ()->Unit = {},
onDragCancelCustomAction: ()->Unit = {},
content: @Composable (() -> Unit),
) {
var currentPosition by remember { mutableStateOf(Offset.Zero) }
val currentState = LocalDragTargetInfo.current
Box(modifier = modifier
.onGloballyPositioned {
currentPosition = it.localToWindow(Offset.Zero)
}
.pointerInput(Unit) {
detectDragGesturesAfterLongPress(onDragStart = {
currentState.dataToDrop = dataToDrop
currentState.isDragging = true
currentState.dragPosition = currentPosition + it
currentState.draggableComposable = content
}, onDrag = { change, dragAmount ->
change.consume()
currentState.dragOffset += Offset(dragAmount.x, dragAmount.y)
onDragCustomAction()
}, onDragEnd = {
currentState.isDragging = false
currentState.dragOffset = Offset.Zero
}, onDragCancel = {
onDragCancelCustomAction()
currentState.dragOffset = Offset.Zero
currentState.isDragging = false
})
}) {
content()
}
}
@Composable
fun <T> DropTarget(
modifier: Modifier,
content: @Composable() (BoxScope.(isInBound: Boolean, data: T?) -> Unit)
) {
val dragInfo = LocalDragTargetInfo.current
val dragPosition = dragInfo.dragPosition
val dragOffset = dragInfo.dragOffset
var isCurrentDropTarget by remember {
mutableStateOf(false)
}
Box(modifier = modifier.onGloballyPositioned {
it.boundsInWindow().let { rect ->
isCurrentDropTarget = rect.contains(dragPosition + dragOffset)
}
}) {
val data =
if (isCurrentDropTarget && !dragInfo.isDragging) dragInfo.dataToDrop as T? else null
content(isCurrentDropTarget, data)
}
}
internal class DragTargetInfo {
var isDragging: Boolean by mutableStateOf(false)
var dragPosition by mutableStateOf(Offset.Zero)
var dragOffset by mutableStateOf(Offset.Zero)
var draggableComposable by mutableStateOf<(@Composable () -> Unit)?>(null)
var dataToDrop by mutableStateOf<Any?>(null)
}
使用此代码,我应该能够将黑色方块从一列移动到另一列。问题是,例如,如果我移动第一个项目,它会起作用,但是如果我尝试移动第二个项目(现在成为列表中的第一个项目),则显示的值与前一个项目相同。
您可以在这张 gif 中看到一个示例:
问题似乎是传递给 DragTarget 中的 dataToDrop 的值没有更新。我做错了什么?
我怀疑错误的发生是由于存储
items
数据结构的方式造成的。在官方文档中他们说:
警告:
在 Compose 中使用可变对象(例如或ArrayList<T>
)作为状态会导致用户在应用程序中看到不正确或过时的数据。不可观察的可变对象(例如 ArrayList 或可变数据类)不可被 Compose 观察,并且在更改时不会触发重组。mutableListOf()
mutableStateListOf()
代替:
val items = remember {
mutableStateListOf(
mutableStateListOf(5,6,7,8),
mutableStateListOf(),
mutableStateListOf(),
mutableStateListOf()
)
}
请反馈这是否解决了问题。