我是Jetpack Compose的新手,我正在try 使用要从一列移动到另一列的项目进行拖放屏幕.我从this个链接中汲取灵感,创建了以下文件:

TaskColumns.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))
                            }
                        }
                    }

                }
            }
        }
    }
}

DragAndDrop.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)
}

使用此代码,我应该能够将黑色方块从一列移动到另一列.问题是,例如,如果我移动第一个项目,它就会起作用,但如果我try 移动第二个项目(现在成为列表中的第一个),则显示的值与前一个项目相同.

您可以在此gif中看到一个示例:

Animated example

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

推荐答案

我怀疑该错误的发生是由于您存储items数据 struct 的方式造成的.在official documentation人中他们说:

注意:
在Compose中使用ArrayList<T>mutableListOf()等可变对象作为状态会导致您的用户在应用程序中看到不正确或陈旧的数据.不可观察的可变对象(例如ArrayList或可变数据类)无法由Compose观察,并且在它们发生变化时不会触发重新组合.

请try 使用mutableStateListOf():

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

此外,您需要为DragTarget个组合物定义key,如下所示:

items[column].forEachIndexed { index, item ->

    key(item) {
        DragTarget(
            //...
        ) {
            //...
        }
    }
}

Android相关问答推荐

ava.lang. ClassNotFound异常:没有找到类com.example.myapp.MyApp"

Media会话无法在android 10及以上版本中播放音频

view喷气背包中找不到模型组成

如何将文本相对于喷气背包中的图标垂直居中?

在Android中点击滑动时触发的手势

在命令行Android应用程序开发中苦苦挣扎

BroadCastReceiver的onReceive方法中的Intent上的Extras为空

未解析的引用:视图模型

如何禁用自动登录 google play games services android unity?

根据另一个数组的值对数组进行排序

如何从包装在泛型中的 retrofit 调用中检索密钥?

服务似乎在启动时忽略传递的变量

在事件中使用 Context/Toast 时不需要的重组 - Jetpack Compose

自定义 Compose Arrangement 以在 LazyRow/LazyColumn 的开头和结尾添加额外的间距

如何在组件之间导航

如何在屏幕旋转或系统主题更改后将光标移动到 TextField 的末尾并保持键盘显示?

react 从输入中找到路径'lib/arm64-v8a/libfbjni.so'的本机2个文件

JCenter 是否永久关闭(10 月 31 日)?

Hilt 依赖注入重复绑定错误

新的内部测试应用程序版本不适用于测试人员,即使它说它们是