iOS:Swift - 如何在触摸地图上添加精确定位并获取该位置的详细地址?

Posted

技术标签:

【中文标题】iOS:Swift - 如何在触摸地图上添加精确定位并获取该位置的详细地址?【英文标题】:iOS : Swift - How to add pinpoint to map on touch and get detailed address of that location? 【发布时间】:2016-03-29 15:20:49 【问题描述】:

我想在触摸 ios 地图时添加注释并获取相应位置的详细地址(地标)。我如何在 Swift 中实现这一点?

提前致谢。

【问题讨论】:

他特别提到了“地标”。我发现这篇文章是因为我正在寻找如何从注释中获取地标。我很高兴这个线程会回答这个问题,因为这就是 OP 所要求的。但是,无论如何,一个只解决了一半问题的答案不能被认为是完整的。 使用这个 -> github.com/almassapargali/LocationPicker 【参考方案1】:

要对地图上的触摸做出反应,您需要为 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 委托函数即可绘制注释。一个简单的谷歌搜索应该让你得到剩下的。

【讨论】:

我为 swift 3 @Neo42 添加了一个编辑。一旦经过同行评审,您就可以看到它 这个“答案”不回答用户的问题。 OP 询问如何获得地标。 除非没有其他选项,否则您永远不应使用字符串文字来标识选择器。相反,请使用#selector(handleTap(gestureRecognizer:))。这可以防止拼写错误并允许您使用 Xcode 的重构工具。【参考方案2】:
 //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)。【参考方案3】:

由于其他答案充分涵盖了如何处理触摸事件,下一步是使用 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)"
            
        
    

【讨论】:

【参考方案4】:

这是一个有效的 Xcode 10.1, Swift 4.2 项目,带有 MapKit 委托 来控制注释(图钉颜色、图钉图像等)并委托处理点击添加的注释: 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")
        
    
  

【讨论】:

这个“答案”不回答用户的问题。 OP 询问如何获得地标。 请再仔细阅读问题,然后再想一想。问题是如何在触摸时添加注释并获取地址。我的回答涵盖了其中的 50%。仅仅因为它没有回答你的问题,并不意味着它是错误的。 引用 OP:“...获取详细地址(地标)”,他要求的是地标。 不,但看起来你是。是的,他要求两件事:放置注释和获取地标,而不仅仅是详细地址。没有一个答案可以解决地标问题。部分答案的部分功劳。 顺便说一句,我从来没有说过你的答案是错误的。但 50% 的答案不是答案。如果有人问我从柏林到法兰克福的路线,我说:“走到街的尽头,左转”,我几乎不会因为回答最初的问题而受到鼓掌。【参考方案5】:

对于 Swift 4,我转换了 Swift 3 示例,因为另一个 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 询问如何获得地标。【参考方案6】:

斯威夫特 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 询问如何获得地标。【参考方案7】:

对于 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 询问如何获得地标。

以上是关于iOS:Swift - 如何在触摸地图上添加精确定位并获取该位置的详细地址?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ti.map 上的苹果地图上添加“当前位置按钮”(导航标记)

Swift:禁用对 UITableViewCell 的触摸

如何在 IOS/SWIFT/OBJ-C/CORDOVa 上获取手指 ID(哪个手指用于触摸 ID)或唯一触摸 ID

使用 Swift 通过触摸任意位置来关闭 iOS 键盘

如何使用 swift 在 IOS 地图上叠加图像

如何在 swift/iOS 中更新谷歌地图标记位置