如何立即获得可拖动的 MKAnnotationView?

Fre*_*uid 3 ios swift

下面的代码有效,并为我提供了一个可拖动的注释视图。但是,我注意到注释视图从一开始就不能拖动,而只能在手指在注释视图上停留片刻之后才能拖动。当直接进入拖动运动时,拖动不会影响注释视图,而是平移地图。这当然不像拖放的感觉。无论是在设备上还是在模拟器中。

ViewController(MapView 的委托)

override func viewDidLoad() {
    /// ...
    let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(addPin))
    mapView.addGestureRecognizer(gestureRecognizer)
}

func addPin(gestureRecognizer: UIGestureRecognizer) {
    if gestureRecognizer.state != UIGestureRecognizerState.Began {
        return
    }
    for annotation in mapView.annotations {
        mapView.removeAnnotation(annotation)
    }
    let touchLocationInView = gestureRecognizer.locationInView(mapView)
    let coordinate = mapView.convertPoint(touchLocationInView, toCoordinateFromView: mapView)
    let annotation = DragAnnotation(coordinate: coordinate, title: "draggable", subtitle: "")
    mapView.addAnnotation(annotation)
}

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation.isKindOfClass(DragAnnotation) {
        let reuseIdentifier = "DragAnnotationIdentifier"
        var annotationView: MKAnnotationView!
        if let dequeued = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseIdentifier) {
            annotationView = dequeued
        } else {
            annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
        }
        annotationView.annotation = annotation
        annotationView.image = UIImage(named: "bluedisk2")
        annotationView.canShowCallout = false
        annotationView.draggable = true
        return annotationView
    }
    return nil
}

func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
    switch (newState) {
    case .Starting:
        view.dragState = .Dragging
    case .Ending, .Canceling:
        view.dragState = .None
    default: break
    }
}
Run Code Online (Sandbox Code Playgroud)

拖动注释

import UIKit
import MapKit

class DragAnnotation : NSObject, MKAnnotation {
    var coordinate: CLLocationCoordinate2D {
        didSet {
            print(coordinate)
        }
    }
    var title: String?
    var subtitle: String?

    init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String) {
        self.coordinate = coordinate
        self.title = title
        self.subtitle = subtitle
    }  
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 5

我不认为您可以更改可拖动延迟,但您可以禁用它并添加您自己的没有延迟(或更短延迟)的拖动手势:

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation is MKUserLocation { return nil }

    var view = mapView.dequeueReusableAnnotationViewWithIdentifier("Foo")
    if view == nil {
        view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "Foo")
        view?.draggable = false

        let drag = UILongPressGestureRecognizer(target: self, action: #selector(handleDrag(_:)))
        drag.minimumPressDuration = 0 // set this to whatever you want
        drag.allowableMovement = .max
        view?.addGestureRecognizer(drag)
    } else {
        view?.annotation = annotation
    }

    return view
}

private var startLocation = CGPointZero

func handleDrag(gesture: UILongPressGestureRecognizer) {
    let location = gesture.locationInView(mapView)

    if gesture.state == .Began {
        startLocation = location
    } else if gesture.state == .Changed {
        gesture.view?.transform = CGAffineTransformMakeTranslation(location.x - startLocation.x, location.y - startLocation.y)
    } else if gesture.state == .Ended || gesture.state == .Cancelled {
        let annotationView = gesture.view as! MKAnnotationView
        let annotation = annotationView.annotation as! DragAnnotation

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

        annotationView.transform = CGAffineTransformIdentity
        annotation.coordinate = mapView.convertPoint(updatedLocation, toCoordinateFromView: mapView)
    }
}
Run Code Online (Sandbox Code Playgroud)

顺便说一下,如果您要更改coordinate注释的 ,您需要dynamic在自定义类coordinate声明中添加关键字,以便发出适当的 KVO 通知。

class DragAnnotation: NSObject, MKAnnotation {
    dynamic var coordinate: CLLocationCoordinate2D
    var title: String?
    var subtitle: String?

    init(coordinate: CLLocationCoordinate2D, title: String? = nil, subtitle: String? = nil) {
        self.coordinate = coordinate
        self.title = title
        self.subtitle = subtitle
        super.init()
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,在此示例中,我将延迟设置为零。这意味着如果您点击注释(“显示标注”的典型 UI),这可能会阻止其正常工作。它将将此视为非常短的阻力。这就是为什么标准 UI 在拖动之前需要延迟长按。

因此,出于这个原因,我个人会犹豫是否覆盖上面显示的这种行为,因为它与最终用户熟悉的标准地图行为不同。如果您的地图的行为与用户设备上的任何其他地图不同,这可能会令人沮丧。