我正在尝试使用 Jetbrains Compose(桌面/JVM)实现具有可移动(通过拖动)工作区和图形节点的图形视图(图形节点为 Card
s)。
我设法制作了可拖动的图形节点 (GraphNodeBox
),然后我想在外部节点容器 (ViewBox
) 上检测到拖动时移动所有节点,但状态的变化没有' t 触发图节点的重组。我调试记录了状态更改(当所有节点偏移都更新时)并且它是在拖动手势上执行的,但 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) }
)
}
}
看起来外部可组合的状态更新对嵌套的可组合没有影响。
我可能错过了 Jetbrains Compose 的想法,应该以其他方式实现它,但我想不出正确的实现。