12

I'm trying to make an iPhone app which requires users to be able to long press on a place on a map view to drop a pin there. Does anybody know how this is done?

The behaviour is observable in apple maps when you long press on the screen. It will drop a pin and present an annotation saying "dropped pin"

Matt Spoon
  • 2,760
  • 5
  • 25
  • 41

4 Answers4

36
  1. add UILongPressGestureRecognizer to your MapView

    var uilgr = UILongPressGestureRecognizer(target: self, action: "addAnnotation:")
    uilgr.minimumPressDuration = 2.0
    
    map.add (uilgr)
    
    //IOS 9
    map.addGestureRecognizer(uilgr) 
    
  2. Add annotation on Long press detect - func:

    func addAnnotation(gestureRecognizer:UIGestureRecognizer){
        if gestureRecognizer.state == UIGestureRecognizerState.Began {
            var touchPoint = gestureRecognizer.locationInView(map)
            var newCoordinates = map.convertPoint(touchPoint, toCoordinateFromView: map)
            let annotation = MKPointAnnotation()
            annotation.coordinate = newCoordinates
    
            CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: newCoordinates.latitude, longitude: newCoordinates.longitude), completionHandler: {(placemarks, error) -> Void in
                if error != nil {
                    println("Reverse geocoder failed with error" + error.localizedDescription)
                    return
                }
    
            if placemarks.count > 0 {
                let pm = placemarks[0] as! CLPlacemark
    
                // not all places have thoroughfare & subThoroughfare so validate those values
                annotation.title = pm.thoroughfare + ", " + pm.subThoroughfare
                annotation.subtitle = pm.subLocality
                self.map.addAnnotation(annotation)
                println(pm)
            }
            else {
                annotation.title = "Unknown Place"
                self.map.addAnnotation(annotation)
                println("Problem with the data received from geocoder")
            }
            places.append(["name":annotation.title,"latitude":"\(newCoordinates.latitude)","longitude":"\(newCoordinates.longitude)"])
        })
    }
    }
    
  3. or you can add annotation without any title:

    func action(gestureRecognizer:UIGestureRecognizer){
        var touchPoint = gestureRecognizer.locationInView(map)
        var newCoordinates = map.convertPoint(touchPoint, toCoordinateFromView: map)
        let annotation = MKPointAnnotation()
        annotation.coordinate = newCoordinates
        map.addAnnotation(annotation)
    }
    
itzhar
  • 12,743
  • 6
  • 56
  • 63
  • 9
    It seems in iOS 9 the `map.add(uilgr)` should be `map.addGestureRecognizer (uilgr)` – Ri_ Dec 09 '15 at 08:28
11

1) Instantiate a UILongPressGestureRecognizer and add it to the MKMapView.

2) When the selector gets called after the user has a long press, call the addAnnotation method in MKMapView with the appropriate title and coordinate.

3) Then make sure you conform to the MKMapViewDelegate and implement viewForAnnotation: which will be called right after you add the annotation and return a MKPinAnnotationView

Joe
  • 8,868
  • 8
  • 37
  • 59
Josh Hamet
  • 957
  • 8
  • 10
  • 3
    with step 2: How am I to find the appropriate coordinate? – Matt Spoon Jun 16 '15 at 04:15
  • 4
    convertPoint(_:toCoordinateFromView:) will allow you to convert the CGPoint selected which can be obtained from the UILongPressGestureRecognizer to the actual coordinate in the MKMapView – Josh Hamet Jun 16 '15 at 04:18
  • convertPoint must be used on the MKMapView itself, and not a "regular" ViewController. –  Feb 13 '19 at 15:32
7

First declare UIGestureRecognizer in viewDidLoad

let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(addWaypoint(longGesture:)))
mapView.addGestureRecognizer(longGesture)

Second add the function for longPress

@objc func addWaypoint(longGesture: UIGestureRecognizer) {

    let touchPoint = longGesture.location(in: mapView)
    let wayCoords = mapView.convert(touchPoint, toCoordinateFrom: mapView)
    let location = CLLocation(latitude: wayCoords.latitude, longitude: wayCoords.longitude)
    myWaypoints.append(location)

    let wayAnnotation = MKPointAnnotation()
    wayAnnotation.coordinate = wayCoords
    wayAnnotation.title = "waypoint"
    myAnnotations.append(wayAnnotation)
}

I recommend creating the annotations in an array that will serve you later if you want to delete it, like this...

var myAnnotations = [MKPointAnnotation]()

If you have different annotations, you can delete only the annotations you want, for that when you add a new annotation add to the array. To delete only one group of annotations just do the following

for dots in myAnnotations{
    mapView.removeAnnotation(dots)
}

To delete all annotations try

mapView.removeAnnotations(mapView.annotations)

Apologies for the translation....

michael-martinez
  • 767
  • 6
  • 24
oscar castellon
  • 3,048
  • 30
  • 19
2

Update Swift3

func action(gestureRecognizer:UIGestureRecognizer){
    let touchPoint = gestureRecognizer.location(in: mapView)
    let newCoordinates = mapView.convert(touchPoint, toCoordinateFrom: mapView)
    let annotation = MKPointAnnotation()
    annotation.coordinate = newCoordinates
    mapView.addAnnotation(annotation)
}
Icarus
  • 1,627
  • 7
  • 18
  • 32
K. Sergey
  • 157
  • 1
  • 8