iOS : Swift - How to add pinpoint to map on touch and get detailed address of that location?
Asked Answered
A

7

25

I want to add annotation on touch of iOS map and fetch the detailed address (Placemark) of respective location. How I can achieve this in Swift?

Thanks in advance.

Arkansas answered 23/12, 2015 at 8:26 Comment(2)
He specifically mentions "Placemark." I found this post because I was searching for how to get a Placemark from an Annotation. I was encouraged that this thread would answer that, because that's what the OP is asking for. But, in any case, an answer that only address half the question cannot be considered complete.Cellule
use this -> github.com/almassapargali/LocationPickerHornet
S
28

To react to the touch on map you need to set up a tap recogniser for the mapView

in viewDidLoad:

let gestureRecognizer = UITapGestureRecognizer(
                              target: self, action:#selector(handleTap))
    gestureRecognizer.delegate = self
    mapView.addGestureRecognizer(gestureRecognizer)

Handle the tap and get the tapped location coordinates:

func handleTap(gestureRecognizer: UITapGestureRecognizer) {
    
    let location = gestureRecognizer.location(in: mapView)
    let coordinate = mapView.convert(location, toCoordinateFrom: mapView)
    
    // Add annotation:
    let annotation = MKPointAnnotation()
    annotation.coordinate = coordinate
    mapView.addAnnotation(annotation)
}

Now you only have to implement the MKMapView delegate functions to draw the annotations. A simple google search should get you the rest of that.

Spradlin answered 23/12, 2015 at 8:45 Comment(3)
I've added an edit for swift 3 @Neo42. You'll be able to see it once it's peer reviewedLapidify
This "answer" doesn't answer the user's question. The OP asked how to get a Placemark.Cellule
You should never use a string literal to identify a selector unless there is no other option. Instead, use #selector(handleTap(gestureRecognizer:)). This prevents typos and allows you to use Xcode's refactoring tools.Sirkin
L
10

Here is a working Xcode 10.1, Swift 4.2 project with MapKit delegates to control the annotations (pin color, pin image etc.) and delegate to handle a click on the added annotation: Github Project

import UIKit
import MapKit

class ViewController: UIViewController {

@IBOutlet weak var mapView: MKMapView!

override func viewDidLoad() {
    super.viewDidLoad()
    mapView.delegate = self
    let longTapGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap))
    mapView.addGestureRecognizer(longTapGesture)
}

@objc func longTap(sender: UIGestureRecognizer){
    print("long tap")
    if sender.state == .began {
        let locationInView = sender.location(in: mapView)
        let locationOnMap = mapView.convert(locationInView, toCoordinateFrom: mapView)
        addAnnotation(location: locationOnMap)
    }
}

func addAnnotation(location: CLLocationCoordinate2D){
        let annotation = MKPointAnnotation()
        annotation.coordinate = location
        annotation.title = "Some Title"
        annotation.subtitle = "Some Subtitle"
        self.mapView.addAnnotation(annotation)
}
}

extension ViewController: MKMapViewDelegate{

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    guard annotation is MKPointAnnotation else { print("no mkpointannotaions"); return nil }

    let reuseId = "pin"
    var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView

    if pinView == nil {
        pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        pinView!.canShowCallout = true
        pinView!.rightCalloutAccessoryView = UIButton(type: .infoDark)
        pinView!.pinTintColor = UIColor.black
    }
    else {
        pinView!.annotation = annotation
    }
    return pinView
}

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
    print("tapped on pin ")
}

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    if control == view.rightCalloutAccessoryView {
        if let doSomething = view.annotation?.title! {
           print("do something")
        }
    }
  }
}
Labial answered 21/12, 2018 at 12:42 Comment(7)
This "answer" doesn't answer the user's question. The OP asked how to get a Placemark.Cellule
Please read the question carefully again and then think about it again. The Question is how to add an annotation on touch & get the address. My answer covers 50% of it. Just because it doesn't answer your question, doesn't mean it is false.Labial
To quote the OP: "...fetch the detailed address (Placemark)" he's asking for a Placemark.Cellule
No, but it seems you are. Yes, he asked for two things: placing an Annotation and getting a Placemark, not just the detailed address. Not a single answer addresses the Placemark issue. Partial credit for partial answers.Cellule
I never said your answer was false, by the way. But a 50% answer is not an answer. If someone asked for directions from Berlin to Frankfurt and I said, "Go to the end of the street and turn left," I'd hardly be applauded for answering the original question.Cellule
Nothing you are 100% right. Hope you find your answers. Have a good day.Labial
Let us continue this discussion in chat.Cellule
T
2

Swift 4:

 @IBOutlet weak var mapView: MKMapView!

 func handleLongPress (gestureRecognizer: UILongPressGestureRecognizer) {
    if gestureRecognizer.state == UIGestureRecognizerState.began {
        let touchPoint: CGPoint = gestureRecognizer.location(in: mapView)
        let newCoordinate: CLLocationCoordinate2D = mapView.convert(touchPoint, toCoordinateFrom: mapView)
        addAnnotationOnLocation(pointedCoordinate: newCoordinate)
    }
}

func addAnnotationOnLocation(pointedCoordinate: CLLocationCoordinate2D {
    let annotation = MKPointAnnotation()
    annotation.coordinate = pointedCoordinate
    annotation.title = "Loading..."
    annotation.subtitle = "Loading..."
    mapView.addAnnotation(annotation)
}
Third answered 18/1, 2018 at 8:59 Comment(1)
This "answer" doesn't answer the user's question. The OP asked how to get a Placemark.Cellule
S
1

For Swift 4 I converted the Swift 3 example as the other Swift 4 one did not work for me: (note I'm using 'mapview' instead of 'mapView'just to fit in with other code

        let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
        gestureRecognizer.delegate = self
        mapview.addGestureRecognizer(gestureRecognizer)


@objc func handleTap(_ gestureReconizer: UILongPressGestureRecognizer)
    {

        let location = gestureReconizer.location(in: mapview)
        let coordinate = mapview.convert(location,toCoordinateFrom: mapview)

        // Add annotation:
        let annotation = MKPointAnnotation()
        annotation.coordinate = coordinate
        mapview.addAnnotation(annotation)
    }
September answered 20/9, 2018 at 11:13 Comment(1)
This "answer" doesn't answer the user's question. The OP asked how to get a Placemark.Cellule
D
1

Since the other answers adequately cover how to handle the touch event, the next step is to use CLGeocoder to preform a reverse-geocoding, which will convert a location value into a list of placemarks at that location.

func handleTap(gestureReconizer: UILongPressGestureRecognizer) {

    let location = gestureReconizer.locationInView(mapView)
    let coordinate = mapView.convertPoint(location,toCoordinateFromView: mapView)

    let geocoder = CLGeocoder()
    geocoder.reverseGeocodeLocation(coordinate) { (placemarks, error) in 
        if let places = placemarks {
            for place in places {
                print("found placemark \(place.name) at address \(place.postalAddress)"
            }
        }
    }
}
Doorplate answered 3/10, 2019 at 17:19 Comment(0)
D
0

For swift 3.0

let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
gestureRecognizer.delegate = self
mapView.addGestureRecognizer(gestureRecognizer)

func handleTap(_ gestureReconizer: UILongPressGestureRecognizer) {

    let location = gestureReconizer.locationInView(mapView)
    let coordinate = mapView.convertPoint(location,toCoordinateFromView: mapView)

    // Add annotation:
    let annotation = MKPointAnnotation()
    annotation.coordinate = coordinate
    mapView.addAnnotation(annotation)
}
Dextrous answered 12/12, 2017 at 19:53 Comment(1)
This "answer" doesn't answer the user's question. The OP asked how to get a Placemark.Cellule
U
0
 //put this in viewdidload

-->
 mapView.delegate = self
           let longTapGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap))
           mapView.addGestureRecognizer(longTapGesture)
    -->//

@objc func longTap(sender: UIGestureRecognizer){
    print("long tap")
    if sender.state == .began
    {
        let locationInView = sender.location(in: mapView)
        let locationOnMap = mapView.convert(locationInView, toCoordinateFrom: mapView)
        addAnnotation(location: locationOnMap)
        locationManager.stopUpdatingLocation();
        print("the location lattitude is = \(locationOnMap.latitude) and logitude on map = \(locationOnMap.longitude)")
        self.passlat = Double(locationOnMap.latitude)
        self.passlong = Double(locationOnMap.longitude)
        self.getAddressFromLatLon(pdblLatitude: "\(locationOnMap.latitude)", withLongitude: "\(locationOnMap.longitude)")

    }
}


func getAddressFromLatLon(pdblLatitude: String, withLongitude pdblLongitude: String)
{
    var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
    let lat: Double = Double("\(pdblLatitude)")!
    //21.228124
    let lon: Double = Double("\(pdblLongitude)")!
    //72.833770
    let ceo: CLGeocoder = CLGeocoder()
    center.latitude = lat
    center.longitude = lon

    let loc: CLLocation = CLLocation(latitude:center.latitude, longitude: center.longitude)


    ceo.reverseGeocodeLocation(loc, completionHandler:
        {(placemarks, error) in
            if (error != nil)
            {
                print("reverse geodcode fail: \(error!.localizedDescription)")
            }
            let pm = placemarks! as [CLPlacemark]
            if pm.count > 0
            {
                let pm = placemarks![0]
               // print(pm.country)
                //print(pm.locality)
                self.mapaddcontry = pm.country!
                self.mapaddrState = pm.subLocality!
                self.mapaddrcity = pm.locality!
                self.mapaddrPincode = pm.postalCode!

                self.mainname = pm.locality!
                print(pm.subLocality)
                self.subname = pm.subLocality!
                print(pm.thoroughfare)
                print(pm.postalCode)
                print(pm.subThoroughfare)
                var addressString : String = ""
                if pm.subLocality != nil
                {
                    addressString = addressString + pm.subLocality! + ", "
                }
                if pm.thoroughfare != nil {
                    addressString = addressString + pm.thoroughfare! + ", "
                }
                if pm.locality != nil {
                    addressString = addressString + pm.locality! + ", "
                }
                if pm.country != nil
                {
                    addressString = addressString + pm.country! + ", "
                }
                if pm.postalCode != nil
                {
                    addressString = addressString + pm.postalCode! + " "
                }

                self.addr.text = addressString
                print(addressString)
                self.mapaddrtxt.text = addressString
                self.location_name = addressString

            }
    })

}
Unijugate answered 7/11, 2019 at 6:31 Comment(1)
@anurag mkmapView.addAnnotation(locationOnMap as! MKAnnotation) it's getting an error Could not cast value of type '__C.CLLocationCoordinate2D' (0x10c801f88) to '__C.MKAnnotation' (0x7fd45a94e6c8).Quadrate

© 2022 - 2024 — McMap. All rights reserved.