列表的可变状态未正确更新

问题描述 投票:0回答:1

我是 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 中看到一个示例:

Animated example

问题似乎是传递给 DragTarget 中的 dataToDrop 的值没有更新。我做错了什么?

android android-jetpack-compose mutablelist
1个回答
0
投票

我怀疑错误的发生是由于存储

items
数据结构的方式造成的。在官方文档中他们说:

警告:
在 Compose 中使用可变对象(例如

ArrayList<T>
mutableListOf()
)作为状态会导致用户在应用程序中看到不正确或过时的数据。不可观察的可变对象(例如 ArrayList 或可变数据类)不可被 Compose 观察,并且在更改时不会触发重组。

请尝试使用

mutableStateListOf()
代替:

val items = remember {
    mutableStateListOf(
        mutableStateListOf(5,6,7,8),
        mutableStateListOf(),
        mutableStateListOf(),
        mutableStateListOf()
    )
}

请反馈这是否解决了问题。

© www.soinside.com 2019 - 2024. All rights reserved.