在移动时跟踪 MKAnnotation 拖动?

Track MKAnnotation drag as it moves?

是否可以跟踪 MKAnnotation 在拖动过程中移动 时的坐标变化?我遵循了管理视图 dragState 的方法,但是如果我放入一些打印件,似乎 dragging 状态(在 mapView(mapView, view, newState, oldState) 中)只在开始时发生一次阻力。然后当我释放时,我得到 ending。但是移动时没有实时更新。

我可以启动一个计时器,在拖动过程中 "polls" 注释,但我希望有一些不那么骇人听闻的东西。

很抱歉来晚了。我有同样的需求,遇到了你的post。这是我所做的。

首先是我的地图视图委托视图的注释方法。使注释视图可拖动并添加手势识别器。 (我的DetailAnnotationView是MKAnnotationView的一个子类,它给党带来了什么,与我们的重点不相关。)

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        var annotationView = overviewMap.dequeueReusableAnnotationView(withIdentifier: DetailAnnotationView.reuseIdentifier) as? DetailAnnotationView
        if annotationView == nil {
            annotationView = DetailAnnotationView(annotation: nil)
            annotationView!.isDraggable = true
            let recognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressGestureHandler))
            recognizer.allowableMovement = CGFloat.infinity
            recognizer.delegate = self
            annotationView!.addGestureRecognizer(recognizer)
        }
        annotationView!.updateBounds(self)
        return annotationView
    }

接下来是手势处理程序。 detailAnnotation 是一个 MKPointAnnotation。请注意,我正在使用 MKMapView.convert 的结果来重新定位地图。当然,你可以随意使用它。

@objc func longPressGestureHandler(_ recognizer: UILongPressGestureRecognizer) {
    switch recognizer.state {
    case .changed:
        guard let annotationView = overviewMap.view(for: detailAnnotation) else { fatalError("Cannot get detail annotation's view") }
        detailMap.region.center = overviewMap.convert(recognizer.location(in: annotationView), toCoordinateFrom: annotationView)
    default: break
    }
}

最后,我允许我的手势识别器与 MapKit 用来拖动注释视图的手势识别器同时运行。

extension DualMapsManager : UIGestureRecognizerDelegate {

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return gestureRecognizer is UILongPressGestureRecognizer && gestureRecognizer.delegate === self && otherGestureRecognizer is UILongPressGestureRecognizer
    }
}

好了。如果您最终选择了轮询,那么您现在有了另一种选择。如果您找到了不同的解决方案,那为什么不 post 呢?

I did 最终完成了轮询机制工作。三种方法

// helper method to trigger a redraw of the renderer associated with a given overlay
// despite the documentations claim to otherwise, it seems that the parameterized
// version of setNeedsDisplay does a better job of updating caches
func redrawOverlay(_ overlay:RegionOverlay?) {
    guard let overlay = overlay, let renderer = self.mapView.renderer(for: overlay) else { return }
    renderer.setNeedsDisplay(self.mapView.visibleMapRect)
}

// the "worker" method that is called once we enter .dragging state and then
// repeatedly calls myself as long as that .dragging state stays in effect
func updateMapWhileDragging(_ annotationView:MKAnnotationView, first:Bool = false) {
    if annotationView.dragState == .dragging {
        let point = annotationView.bounds.midMid
        let coordinate = self.mapView.convert(point, toCoordinateFrom: annotationView)
        if let annotation = annotationView.annotation as? RegionEditingAnnotation {
            if first {
                annotation.beginMove(at: coordinate)
            }
            else {
                annotation.move(to: coordinate)
            }
            if let overlay = self.findOverlay(region: annotation.region) {
                overlay.region = annotation.region
                self.redrawOverlay(overlay)
            }
        }
        // ding with this method again in 40ms
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(40)) {
            self.updateMapWhileDragging(annotationView)
        }
    }
}

// the MK delegate method where we can handle most of the states with
// boilerplate responses
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationView.DragState, fromOldState oldState: MKAnnotationView.DragState) {
    self.shouldZoom = false
    switch newState {
    case .starting:
        view.setDragState(.dragging, animated: true)
    case .dragging:
        self.updateMapWhileDragging(view, first: true)
    case .ending:
        if let annotation = view.annotation as? RegionEditingAnnotation, let mappable = self.selectedOverlay?.mappable {
            annotation.endMoves(at: annotation.coordinate)
            self.selectedOverlay?.region = annotation.region
            self.redrawOverlay(self.selectedOverlay)
            mappable.regionPush(annotation.region)
            view.setDragState(.none, animated: true)
            // call the didSet function directly, because the compiler's too "smart" to reset the same value
            self.selectedOverlay_didSet(from: self.selectedOverlay)
        }
    case .canceling:
        view.setDragState(.none, animated: true)
    case .none:
        break
    @unknown default:
        break
    }
}

这是最终的样子。

When/if我回到这个问题上,我会试试@Verticon 的回答。