我正在开发一个可视化的图形/树编辑器,其中每个 node 都表示为一个圆.我需要在这些 node 之间绘制边,在某些情况下,这些边不应该是直线.我想让用户能够交互地操作边,方法是允许用户弯曲边,单击或拖动特定的边,以及在用户点击或单击特定的边 timeshift 动和旋转边的成本或权重(使用DraText表示为文本).成本.我如何才能实现此功能?

我try 使用了TransformmGesture和dragGesture,但我发现这些手势只适用于Composable.

推荐答案

不能将修改器指定给在画布中绘制的内容(Spacer with Modifier.drawBehind)或在绘制修改器中绘制的其他图形.

但您可以将 node 的位置、半径、Angular 和其他视觉属性存储在数据类中,并使用这些类中的值绘制它们.当用户与任何 node 交互时,您将更新这些属性,而读取这些属性的画布将正确绘制您的 node 树.

如果你想检测被touch 的形状是圆的,很容易根据到中心的距离来检测,但如果你想的话,你也可以使用路径.

我发布了一个在屏幕上随机绘制圆圈的示例,因为我没有数据 struct 来绘制 node ,但它应该给出一个如何实现它的 idea .

enter image description here

@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
)

Android相关问答推荐

如何使用单个代码库使用不同的firebase项目创建多个应用程序ID apk

Android编写动画在发布版本中崩溃

Android compose ,在图像中zoom 而不裁剪?

Kotlin DSL:为什么我可以从Play Store获取发布版本的日志(log)?

在Android 14/SDK 34中使用RegisterReceiver的正确方式是什么?

使用 JNI 从 Android 应用程序中使用 Kotlin/Native 预构建共享库

Android kotlin 中闪屏 API 执行完成后如何根据身份验证将用户导航到特定屏幕

如何在 kotlin 中接收带有和不带有可空对象的集合并保持引用相同

如何在 Jetpack Compose 中处理水平滚动手势和变换手势

如何在 Jetpack Compose 中对齐按钮底部中心?

Kotlin Multiplatform Mobile targetSdk 已弃用

如何在没有人窃取令牌的情况下使用我的移动应用程序中的 API

是否可以在 Kotlin 中为 mutableStateOf() 设置自定义设置器

Android:appcompat 和 material 如何从默认创建 appcompat 和 material 视图?

使用默认使用 RTL 语言的项目本地化 android 应用程序

无法 HEAD 'https://jcenter.bintray.com/com/facebook/react/react-native/maven-metadata.xml'

如何在 compose 中使用 BottomSheetScaffold 为底页设置半展开高度?

Android build gradle 文件版本代码自动递增

为什么官方文档用大写字母表示val变量?

Сan 无法从 Firestore 获取数据,没有错误