Kotlin 触发向下组合层次结构的重新组合

Kotlin 触发向下组合层次结构的重新组合,kotlin,android-jetpack-compose,jetbrains-compose,Kotlin,Android Jetpack Compose,Jetbrains Compose,我正在尝试使用可移动(通过拖动)工作区和使用Jetbrains Compose(桌面/JVM)的图形节点实现一个图形视图(图形节点为Cards) 我设法创建了可拖动的图形节点(GraphNodeBox),然后我想在外部节点容器(ViewBox)上检测到拖动时移动所有节点,但状态的更改不会触发图形节点的重新定位。我调试记录了状态更改(当所有节点偏移量都更新时)并在拖动手势上执行,但UI不会重新渲染 @Composable fun ViewBox() { var graphNodes by

我正在尝试使用可移动(通过拖动)工作区和使用Jetbrains Compose(桌面/JVM)的图形节点实现一个图形视图(图形节点为
Card
s)

我设法创建了可拖动的图形节点(
GraphNodeBox
),然后我想在外部节点容器(
ViewBox
)上检测到拖动时移动所有节点,但状态的更改不会触发图形节点的重新定位。我调试记录了状态更改(当所有节点偏移量都更新时)并在拖动手势上执行,但UI不会重新渲染

@Composable
fun ViewBox() {
    var graphNodes by remember {
        mutableStateOf(listOf(GraphNode(Item("Test Item")), GraphNode(Item("Test Item 2"))))
    }

    Box(
        modifier = Modifier.fillMaxSize()
            .background(Color.Magenta)
            .pointerInput(Unit) {
                detectDragGestures { change, dragAmount ->
                    change.consumeAllChanges()
                    graphNodes = graphNodes.map { graphNode ->
                        GraphNode.OffsetLens.modify(graphNode) { it + dragAmount }
                    }
                }
            }
    ) {
        graphNodes.forEach { // it happens only once initially and is not called again when `graphNodes` state is changed
            GraphNodeBox(it)
        }
    }
}

@Composable
fun GraphNodeBox(graphNode: GraphNode) {
    var offset by remember { mutableStateOf(IntOffset(0, 0)) }

    Card(
        modifier = Modifier.padding(5.dp)
            .offset { offset }
            .pointerInput(Unit) {
                detectDragGestures { change, dragAmount ->
                    change.consumeAllChanges()
                    offset += IntOffset(dragAmount.x.toInt(), dragAmount.y.toInt()) // this works like a charm and the offset update triggers recomposition
                }
            }
    ) {
        Row {
            Column(modifier = Modifier.padding(10.dp)) {
                Text(
                    text = graphNode.item.name,
                    style = MaterialTheme.typography.subtitle1
                )
                Text(
                    text = graphNode.item.stereotypes.joinToString { it.toString() },
                    style = MaterialTheme.typography.subtitle2
                )
            }
        }
    }
}

data class GraphNode(
    val item: Item,
    val offset: Offset = Offset(0f, 0f)
) {
    companion object {
        val OffsetLens: Lens<GraphNode, Offset> = PLens(
            get = { it.offset },
            set = { graphNode, value -> graphNode.copy(offset = value) }
        )
    }
}
@Composable
趣味视窗(){
由记忆生成的var图形节点{
可变状态(列表(图形节点(项目(“测试项目”)),图形节点(项目(“测试项目2”)))
}
盒子(
modifier=modifier.fillMaxSize()
.背景(颜色.洋红色)
.pointerInput(单位){
检测到{更改,dragAmount->
change.consumerallchanges()
graphNodes=graphNodes.map{graphNode->
GraphNode.OffsetLens.modify(GraphNode){it+dragAmount}
}
}
}
) {
graphNodes.forEach{//它最初只发生一次,当'graphNodes'状态更改时,不会再次调用
葡萄暗盒(it)
}
}
}
@组合的
有趣的graphNode盒(graphNode:graphNode){
记住{mutableStateOf(IntOffset(0,0))}的var偏移量
卡片(
修饰符=修饰符。填充(5.dp)
.offset{offset}
.pointerInput(单位){
检测到{更改,dragAmount->
change.consumerallchanges()
offset+=IntOffset(dragAmount.x.toInt(),dragAmount.y.toInt())//这就像一个符咒,偏移量更新会触发重新编译
}
}
) {
划船{
列(修饰符=修饰符.填充(10.dp)){
正文(
text=graphNode.item.name,
样式=材料主题。排版。副标题1
)
正文(
text=graphNode.item.stereotypes.joinToString{it.toString()},
样式=材料主题。排版。副标题2
)
}
}
}
}
数据类图形节点(
val项目:项目,
val偏移量:偏移量=偏移量(0f,0f)
) {
伴星{
val偏移:镜头=正压(
get={it.offset},
set={graphNode,value->graphNode.copy(offset=value)}
)
}
}
看起来外部可组合的状态更新对嵌套的可组合没有影响


我可能没有想到Jetbrains Compose,它应该以其他方式实现,但我无法想出正确的实现。

更改
偏移量
值在
Graphnode Box中没有直接的内容
因为
偏移量
没有更改,所以它总是指向相同的
可变状态
实例。这意味着
GraphNodeBox
永远不会真正重新组合。