在移动时跟踪 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 的回答。
是否可以跟踪 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 的回答。