Swift GrecureRecognizers with MKMapKit - Output and Drag

I am trying to use several UIGestureReconizers with MKMapView , on which the user can reset the pin and drag it. He has a callout . I implement this in the TabbarController as well as in the NavigationController . I currently have:

1) A PanGestureRecognizer animates the Tabbar and Navigation elements from the screen. This works great without interfering with panning the map.

2) A TapGestureRecognizer , installed with one click, animates two elements from 1) back to the screen.

3) A TapGestureRecognizer , installed on two cranes, allows you to use the basic zoom functionality of MKMapView . This GestureRecognizer's delegate has a gestureRecognizer. shouldRecognizeSimultaneouslyWithGestureRecognizer set to true

These are the settings in viewDidLoad as follows:

  // This sets up the pan gesture recognizer to hide the bars from the UI. let panRec: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "didDragMap:") panRec.delegate = self mapView.addGestureRecognizer(panRec) // This sets up the tap gesture recognizer to un-hide the bars from the UI. let singleTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "didTapMap:") singleTap.delegate = self singleTap.numberOfTapsRequired = 1 singleTap.numberOfTouchesRequired = 1 mapView.addGestureRecognizer(singleTap) // This sets up the double tap gesture recognizer to enable the zoom facility. // In order to pass double-taps to the underlying `MKMapView` the delegate for this recognizer (self) needs to return true from // gestureRecognizer.shouldRecognizeSimultaneouslyWithGestureRecognizer let doubleTap: UITapGestureRecognizer = UITapGestureRecognizer() doubleTap.numberOfTapsRequired = 2 doubleTap.numberOfTouchesRequired = 1 doubleTap.delegate = self mapView.addGestureRecognizer(doubleTap) // This delays the single-tap recognizer slightly and ensures that it will NOT fire if there is a double-tap singleTap.requireGestureRecognizerToFail(doubleTap) 

My problem arises when I try to implement a UILongPressGestureRecognizer to allow pin output to the map. I am trying to use the following in viewDidLoad :

 // This sets up the long tap to drop the pin. let longTap: UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: "didLongTapMap:") longTap.delegate = self longTap.numberOfTapsRequired = 0 longTap.minimumPressDuration = 0.5 mapView.addGestureRecognizer(longTap) 

This is my action method:

 func didLongTapMap(gestureRecognizer: UIGestureRecognizer) { // Get the spot that was tapped. let tapPoint: CGPoint = gestureRecognizer.locationInView(mapView) let touchMapCoordinate: CLLocationCoordinate2D = mapView.convertPoint(tapPoint, toCoordinateFromView: mapView) var viewAtBottomOfHierarchy: UIView = mapView.hitTest(tapPoint, withEvent: nil) if let viewAtBottom = viewAtBottomOfHierarchy as? MKPinAnnotationView { return } else { if .Began == gestureRecognizer.state { // Delete any existing annotations. if mapView.annotations.count != 0 { mapView.removeAnnotations(mapView.annotations) } annotation = MKPointAnnotation() annotation.coordinate = touchMapCoordinate mapView.addAnnotation(annotation) _isPinOnMap = true findAddressFromCoordinate(annotation.coordinate) updateLabels() } } } 

This really allows the pin to be pushed out on a long crane, and one crane displays the leader, and the second crane for holding and dragging causes the second pin to fall if the drag does not start quickly enough. This second contact falls into the space in which the previous pin was located, and it can be dragged by the user, but the finger is awkward and wrong with the new pin.

I am trying to use the line:

 if let viewAtBottom = viewAtBottomOfHierarchy as? MKPinAnnotationView { 

to return the MKMapView faucet and prevent another pin from being reset, but the return will never be called, although the breakpoint on this line indicates that viewAtBottom is of type MapKit.MKPinAnnotationView . Any ideas I'm wrong about?

+7
ios swift drag-and-drop mkmapview uigesturerecognizer
source share
1 answer

I think that I could answer your problem if I understood correctly. You are having problems when one pin is discarded and then drags the screen around without placing the other pin, right? This is my code, I am doing something similar, and this seems to work for me. import UIKit import MapKit import CoreLocation

 class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate { @IBOutlet var map: MKMapView! var manager = CLLocationManager() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let uilpgr = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.longpress(gestureRecognizer:))) uilpgr.minimumPressDuration = 2 map.addGestureRecognizer(uilpgr) if activePlace == -1 { manager.delegate = self manager.desiredAccuracy = kCLLocationAccuracyBest manager.requestWhenInUseAuthorization() manager.startUpdatingLocation() self.map.showsUserLocation = true } else { //GET PLACE DETAILS TO DISPLAY ON MAP if places.count > activePlace { if let name = places[activePlace]["name"]{ if let lat = places[activePlace]["lat"]{ if let lon = places[activePlace]["lon"]{ if let latitude = Double(lat) { if let longitude = Double(lon) { let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05) let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) let region = MKCoordinateRegionMake(coordinate, span) self.map.setRegion(region, animated: true) let annotation = MKPointAnnotation() annotation.coordinate = coordinate annotation.title = name self.map.addAnnotation(annotation) } } } } } } } } func longpress(gestureRecognizer: UIGestureRecognizer) { if gestureRecognizer.state == UIGestureRecognizerState.began { let touchPoint = gestureRecognizer.location(in: self.map) let newCoordinate = self.map.convert(touchPoint, toCoordinateFrom: self.map) let location = CLLocation(latitude: newCoordinate.latitude, longitude: newCoordinate.longitude) var title = "" CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in if error != nil { print(error) } else { if let placemark = placemarks?[0] { if placemark.subThoroughfare != nil { title += placemark.subThoroughfare! + " " } if placemark.thoroughfare != nil { title += placemark.thoroughfare! + " " } } } if title == "" { title = "Added \(NSDate())" } let annotation = MKPointAnnotation() annotation.coordinate = newCoordinate annotation.title = title self.map.addAnnotation(annotation) places.append(["name": title, "lat":String(newCoordinate.latitude), "lon":String(newCoordinate.longitude)]) UserDefaults.standard.set(places, forKey: "places") }) } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { let location = CLLocationCoordinate2D(latitude: locations[0].coordinate.latitude, longitude: locations[0].coordinate.longitude) let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05) let region = MKCoordinateRegion(center: location, span: span) self.map.setRegion(region, animated: true) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 

Hope this helps, the problem may also be that your minimum click duration is only 0.5.

+1
source share

All Articles