iOS:Swift - 如何在触摸时向地图添加标记并获取该位置的详细地址?

25

我想在iOS地图的触摸位置添加注释,并获取相应位置的详细地址(Placemark)。我如何在Swift中实现这一功能?

提前感谢。


他特别提到了“Placemark”。我发现这篇帖子是因为我正在寻找如何从注释中获取Placemark。我受到鼓舞,认为这个线程会回答这个问题,因为这就是OP所问的。但无论如何,只回答一半问题的答案是不完整的。 - Zonker.in.Geneva
1
使用此链接 -> https://github.com/almassapargali/LocationPicker - YodagamaHeshan
7个回答

28

为了在地图上响应触摸操作,您需要为mapView设置一个轻拍手势识别器。

viewDidLoad中:

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

处理点击事件并获取被点击位置的坐标:

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)
}

现在您只需要实现MKMapView委托函数来绘制注释。进行简单的谷歌搜索即可获取其余部分。


1
我已经为Swift 3添加了一个编辑@Neo42。一旦同行审查通过,您就可以看到它。 - KyleHodgetts
这个“答案”并没有回答用户的问题。OP问如何获取一个Placemark。 - Zonker.in.Geneva
除非没有其他选择,否则不应使用字符串字面量来标识选择器。相反,请使用 #selector(handleTap(gestureRecognizer:))。这可以防止拼写错误,并允许您使用 Xcode 的重构工具。 - Peter Schorn

10

这里是一个可用的 Xcode 10.1, Swift 4.2 项目,具有 MapKit代理 来控制注释(标记颜色、标记图像等),并且有委托来处理对添加注释的点击: Github项目

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")
        }
    }
  }
}

这个“答案”并没有回答用户的问题。OP问如何获取一个Placemark。 - Zonker.in.Geneva
请再仔细阅读问题,然后再考虑一下。 问题是如何在触摸时添加注释并获取地址。 我的答案涵盖了其中的50%。仅因它未回答您的问题,并不意味着它是错误的。 - Peter Pohlmann
顺便说一句,我从未说过你的答案是错误的。但是50%的答案并不算是一个答案。如果有人问从柏林到法兰克福的路线,而我回答“走到街道尽头然后左转”,那么我很难因为回答了原问题而受到掌声。 - Zonker.in.Geneva
您说得没错。希望您找到答案,祝您有个愉快的一天。 - Peter Pohlmann
让我们在聊天中继续这个讨论 - Zonker.in.Geneva
显示剩余2条评论

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)
}

这个“答案”并没有回答用户的问题。OP问如何获取一个Placemark。 - Zonker.in.Geneva

1

对于 Swift 4,我将 Swift 3 的示例转换为 Swift 4,因为其他的 Swift 4 示例对我无效: (注意,我使用 'mapview' 而不是 'mapView' 只是为了与其他代码匹配)

        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)
    }

这个“回答”没有回答用户的问题。OP问如何获取一个Placemark。 - Zonker.in.Geneva

1

由于其他答案已经充分涵盖了如何处理触摸事件,下一步是使用CLGeocoder执行反向地理编码,将位置值转换为该位置的地标列表。

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)"
            }
        }
    }
}

0

针对 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)
}

这个“回答”并没有回答用户的问题。OP问如何获取Placemark。 - Zonker.in.Geneva

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

            }
    })

}

@anurag mkmapView.addAnnotation(locationOnMap as! MKAnnotation) 出现错误,无法将类型为 '__C.CLLocationCoordinate2D' (0x10c801f88) 的值转换为 '__C.MKAnnotation' (0x7fd45a94e6c8)。 - Sreekanth G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接