问题描述
以下代码有效,并为我提供了可拖动的批注视图.但是,我注意到注解视图从一开始就不是可拖动的,而是仅在手指在注解视图上停留了一会儿之后才可拖动.直接进入拖动动作时,拖动不会影响注释视图,而是会平移地图.当然,它感觉不像拖放.无论是在设备上还是在模拟器中.
The below code works and gives me a draggable annotation view. However, I've noticed that the annotation view is not draggable from the very beginning on, but rather only after the finger has rested for a short moment on the annotation view. When directly going into a drag movement the dragging doesn't affect the annotation view but instead pans the map. It certainly doesn't feel like drag'n'drop. Both on the device and in the simulator.
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
}
}
DragAnnotation
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
}
}
推荐答案
我认为您无法更改可拖动的延迟,但是可以禁用它并添加没有延迟(或更短延迟)的自己的拖动手势:
I don't think you can change the draggable delay, but you could disable it and add your own drag gesture that has no delay (or a shorter delay):
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)
}
}
如果要更改注释的coordinate
,则需要在自定义类coordinate
声明中添加dynamic
关键字,以便发出适当的KVO通知. /p>
By the way, if you're going to change the coordinate
of an annotation, you will want to add dynamic
keyword to your custom class coordinate
declaration so that the appropriate KVO notifications will be issued.
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()
}
}
注意,在此示例中,我将延迟设置为零.这意味着,如果您点击注释(显示标注"的典型UI),则可能会阻止其正常工作.它将视为一个很短的阻力.这就是为什么标准UI在拖动之前需要长按延迟的原因.
Note, in this example, I set the delay to zero. That means that if you tap on the annotation (the typical UI for "show the callout"), this may prevent that from working correctly. It will treat this as a very short drag. This is why the standard UI requires a delay in the long press before dragging.
因此,由于这个原因,我个人会犹豫重写上面显示的此行为,因为它将不同于最终用户熟悉的标准地图行为.如果您的地图在行为上与用户设备上的任何其他地图不同,则可能是感到沮丧的原因.
So, for this reason, I personally would hesitate to override this behavior shown above because it will be different then standard map behavior that the end user is familiar with. If your map behaves differently than any other maps on the user's device, this could be a source of frustration.
这篇关于如何获得可拖动的MKAnnotationView而没有任何延迟?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!