是否可以有一个可以拖动或选择的点注释视图?

Is it possible to have a point annotation view that can be dragged OR selected?

我有一个 MKMapView 显示一些 MKPinAnnotationView 对象。
我希望能够拖动注释视图,但我也希望能够 select 它。

问题:

当我实现委托函数时

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {…}  

当我按下 注释视图时,会立即调用此函数。它显示警告,从而防止注释视图被拖动。

当我没有实现委托功能时,我可以按预期拖动注释视图。

我认为以下应该是可能的:
- 向下触摸到注释视图。
- 当我拖动时,移动注释视图。
- 否则,即 当我从注释视图中触摸 时,select 它。

我怎样才能做到这一点?

编辑:

我的引脚注释视图没有标注。相反,当它被 selected 时,它会显示一个 UIAlertController 以便用户可以选择进一步的操作。如果是这样,mapView 会变暗并且无法访问。

我想要实现的行为是:

如果我触摸引脚注释视图(手指向下),应该不会发生任何事情。

如果我随后移动手指(仍然向下),则应该拖动引脚注释视图。如果我随后抬起手指,引脚注释视图将 不会 被 select 编辑。

但是,如果我不调整手指的模式,而只是抬起它,引脚注释视图 select 编辑(警报视图应该是示)。

我希望这能澄清情况。

一种可能的解决方案是自己处理拖动并使用长按手势来管理您想要的操作(例如何时显示警报)。

此解决方案是围绕 Rob 的 详细答案 构建的,并添加了一些额外的逻辑来处理您问题的具体情况(即 wasMoved 实例 属性).

private var startLocation = CGPoint(x: 0.0, y: 0.0)
private var wasMoved = false

func handleLongPress(_ sender: UILongPressGestureRecognizer) {
    let location = sender.location(in: mapView)

    switch sender.state {
    case .began:
        startLocation = location
    case .changed:
        wasMoved = true
        sender.view?.transform = CGAffineTransform(translationX: location.x - startLocation.x, y: location.y - startLocation.y)
    case .ended, .cancelled:
        if wasMoved {
            let annotationView = sender.view as! MKAnnotationView
            let annotation = annotationView.annotation as! MKPointAnnotation

            let translate = CGPoint(x: location.x - startLocation.x, y: location.y - startLocation.y)
            let originalLocation = mapView.convert(annotation.coordinate, toPointTo: mapView)
            let updatedLocation = CGPoint(x: originalLocation.x + translate.x, y: originalLocation.y + translate.y)

            annotationView.transform = CGAffineTransform.identity
            annotation.coordinate = mapView.convert(updatedLocation, toCoordinateFrom: mapView)
        } else {
            let alert = UIAlertController(title: "Alert", message: "Here is my alert!", preferredStyle: .alert)

            let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
            alert.addAction(ok)

            present(alert, animated: true, completion: nil)
        }
        wasMoved = false
    default:
        break
    }
}

您的 mapView(_:viewFor:) 委托方法如下所示:

extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        guard let reusablePin = mapView.dequeueReusableAnnotationView(withIdentifier: "Pin") as? MKPinAnnotationView else {
            let pin = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "Pin")

            // Add the long press gesture recognizer to the annotation view
            let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
            longPress.minimumPressDuration = 0
            pin.addGestureRecognizer(longPress)

            return pin
        }

        reusablePin.annotation = annotation
        return reusablePin
    }
}