如何创建一个显示具有可移动节点的图形的 UIView?

How to create a UIView that shows a graph with moveable nodes?

注意这里的"graph"是图论图,不是统计图

我正在尝试创建一个图表,其中包含您可以在屏幕上四处移动的节点。我决定使用自定义 UIView subclass - NodeView 来表示节点。为了让它可以移动,我使用了 CocoaPod SEDraggable.

我决定整个图表将由另一个名为 GraphView 的习俗 UIView 绘制。这个 class 有一个 graph 属性 并且设置后,它将通过首先从先前的图形(如果有的话)中删除子视图然后添加新的 NodeView 来绘制整个图形秒。然后我会调用 setNeedsDisplay ,后者又会调用 draw(_:).

在覆盖的 draw 方法中,我将在节点之间绘制线(边,在图论术语中)。

现在我需要检测一个节点被移动了。当它们被移动后,我需要调用 setNeedsDisplay 来重新绘制线条。我环顾四周,明白这可以用 KVO 来完成。但是,我的图形视图需要能够显示具有任意数量节点的图形。这意味着我会将我的节点放入一个数组中。根据这个 post,KVOing 数组是不可能的。

然后我尝试使用 NSNotificationCenter,但我很快发现当视图从 post 移动时没有通知。

然后我发现了这个 post 但 OP 使用 KVO,由于上述原因不能用于我的情况。另外,那个post在Objective-C里面,我不是很懂。

如何创建这样的图表?我正朝着正确的方向前进吗?或者有没有我可以使用的技巧,它不涉及在移动节点时重绘所有内容?感觉每帧重画整个图会很慢

我发现我可以用 CADisplayLink 做到这一点。我没有在 NodeView 移动时重新绘制线条,而是每帧重新绘制它们。

// displayLink is a property of the GraphView class
displayLink = CADisplayLink(target: self, selector: #selector(updateNodePositions))
displayLink.add(to: .main, forMode: .defaultRunLoopMode)

// ...

@objc func updateNodePositions() {
    // nodeViewsToNodes is a dictionary storing all the NodeViews as keys
    // and the corresponding Node (my model object) as values. So here
    // I am basically updating the model based on the view's positions
    for kvp in nodeViewsToNodes {
        kvp.value.x = kvp.key.frame.midX
        kvp.value.y = kvp.key.frame.midY
    }
    setNeedsDisplay()
}

draw(_:)方法会根据模型绘制线条。