我正在开发一个可视化的图形/树编辑器,其中每个 node 都表示为一个圆.我需要在这些 node 之间绘制边,在某些情况下,这些边不应该是直线.我想让用户能够交互地操作边,方法是允许用户弯曲边,单击或拖动特定的边,以及在用户点击或单击特定的边 timeshift 动和旋转边的成本或权重(使用DraText表示为文本).成本.我如何才能实现此功能?
我try 使用了TransformmGesture和dragGesture,但我发现这些手势只适用于Composable.
我正在开发一个可视化的图形/树编辑器,其中每个 node 都表示为一个圆.我需要在这些 node 之间绘制边,在某些情况下,这些边不应该是直线.我想让用户能够交互地操作边,方法是允许用户弯曲边,单击或拖动特定的边,以及在用户点击或单击特定的边 timeshift 动和旋转边的成本或权重(使用DraText表示为文本).成本.我如何才能实现此功能?
我try 使用了TransformmGesture和dragGesture,但我发现这些手势只适用于Composable.
不能将修改器指定给在画布中绘制的内容(Spacer
with Modifier.drawBehind
)或在绘制修改器中绘制的其他图形.
但您可以将 node 的位置、半径、Angular 和其他视觉属性存储在数据类中,并使用这些类中的值绘制它们.当用户与任何 node 交互时,您将更新这些属性,而读取这些属性的画布将正确绘制您的 node 树.
如果你想检测被touch 的形状是圆的,很容易根据到中心的距离来检测,但如果你想的话,你也可以使用路径.
我发布了一个在屏幕上随机绘制圆圈的示例,因为我没有数据 struct 来绘制 node ,但它应该给出一个如何实现它的 idea .
@Preview
@Composable
private fun Test() {
val drawList = remember {
mutableStateListOf<DrawProperties>()
}
var touchIndex by remember {
mutableStateOf(-1)
}
LaunchedEffect(Unit) {
repeat(5) {
val properties = DrawProperties(
center = Offset(
Random.nextInt(100, 1000).toFloat(),
Random.nextInt(100, 1500).toFloat()
)
)
drawList.add(properties)
}
}
Canvas(
modifier = Modifier.fillMaxSize()
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { offset ->
touchIndex = -1
drawList.forEachIndexed { index, drawProperties ->
val isTouched =
isTouched(drawProperties.center, offset, drawProperties.radius)
if (isTouched) {
touchIndex = index
}
}
},
onDrag = { change, dragAmount: Offset ->
val item = drawList.getOrNull(touchIndex)
item?.let { drawItem ->
drawList[touchIndex] = drawItem.copy(
center = drawItem.center.plus(dragAmount),
color = Color.Green
)
}
},
onDragEnd = {
val item = drawList.getOrNull(touchIndex)
item?.let { drawItem ->
drawList[touchIndex] = drawItem.copy(
color = Color.Red
)
}
}
)
}
) {
drawList.forEachIndexed { index, drawProperties ->
if (touchIndex != index) {
drawCircle(
color = drawProperties.color,
center = drawProperties.center,
radius = drawProperties.radius
)
}
}
if (touchIndex > -1) {
drawList.getOrNull(touchIndex)?.let { drawProperties ->
drawCircle(
color = drawProperties.color,
center = drawProperties.center,
radius = drawProperties.radius
)
}
}
}
}
private fun isTouched(center: Offset, touchPosition: Offset, radius: Float): Boolean {
return center.minus(touchPosition).getDistanceSquared() < radius * radius
}
data class DrawProperties(
val center: Offset,
val radius: Float = 80f,
val color: Color = Color.Red
)