在地图中,从当前位置到选定标注的路线指引 - Swift

7

我的应用目前有一个本地搜索功能,可以为搜索结果添加注释。我想设置当您选择注释并点击弹出按钮时,它将在地图应用程序中打开,并提供从当前设备位置到注释的方向。但我遇到了一些问题。

首先,我的注释上没有出现弹出按钮。其次,我认为我没有正确检测到所选注释。

以下是我的搜索和所选注释的代码:

func performSearch() {

    matchingItems.removeAll()
    let request = MKLocalSearchRequest()
    request.naturalLanguageQuery = searchText.text
    request.region = mapView.region

    let search = MKLocalSearch(request: request)

    search.startWithCompletionHandler({(response:
        MKLocalSearchResponse!,
        error: NSError!) in

        if error != nil {
            println("Error occured in search: \(error.localizedDescription)")
        } else if response.mapItems.count == 0 {
            println("No matches found")
        } else {
            println("Matches found")

            for item in response.mapItems as! [MKMapItem] {
                println("Name = \(item.name)")
                println("Phone = \(item.phoneNumber)")

                self.matchingItems.append(item as MKMapItem)
                println("Matching items = \(self.matchingItems.count)")

                var annotation = MKPointAnnotation()
                var coordinates = annotation.coordinate
                annotation.coordinate = item.placemark.coordinate
                annotation.title = item.name
                self.mapView.addAnnotation(annotation)

            }
        }
    })
}



func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!,
    calloutAccessoryControlTapped control: UIControl!) {

        if self.mapView.selectedAnnotations?.count > 0 {

            if let selectedLoc = self.mapView.selectedAnnotations[0] as? MKAnnotation {
                println("Annotation has been selected")
                let currentLoc = MKMapItem.mapItemForCurrentLocation()
                let mapItems = NSArray(objects: selectedLoc, currentLoc)
                let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
                MKMapItem.openMapsWithItems([selectedLoc, currentLoc], launchOptions: launchOptions)
            }
        }

}

非常感谢您的帮助,提前致谢。

1个回答

6

对于第一个问题:

viewForAnnotation委托方法中需要明确设置一个callout按钮(默认的红色标记没有一个)。以下是一种可能的实现的简单示例:

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {

    if annotation is MKUserLocation {
        return nil
    }

    let reuseId = "pin"

    var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
    if pinView == nil {
        pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        pinView!.canShowCallout = true
        pinView!.pinColor = .Purple

        //next line sets a button for the right side of the callout...
        pinView!.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
    }
    else {
        pinView!.annotation = annotation
    }

    return pinView
}

对于第二个问题:
首先,在 `calloutAccessoryControlTapped` 方法中,注释可以直接通过 `view.annotation` 访问,因此在其中使用 `selectedAnnotations` 数组是不必要的。
其次,`openMapsWithItems` 需要一个 `MKMapItem` 对象数组,但在你传递的数组中(`[selectedLoc, currentLoc]`),`selectedLoc` 不是 `MKMapItem` -- 它只是实现了 `MKAnnotation` 的一些对象。
运行这段代码会导致崩溃,并显示如下错误:
“-[MKPointAnnotation dictionaryRepresentation]: unrecognized selector sent to instance”
当地图应用程序试图像 `MKMapItem` 一样使用 `selectedLoc` 时。
相反,你需要从 `selectedLoc` 注释创建一个 `MKMapItem`。这可以通过首先使用 `MKPlacemark(coordinate:addressDictionary:)` 从注释创建一个 `MKPlacemark`,然后使用 `MKMapItem(placemark:)` 从 placemark 创建一个 `MKMapItem` 来完成。
示例:
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!,
    calloutAccessoryControlTapped control: UIControl!) {

        let selectedLoc = view.annotation

        println("Annotation '\(selectedLoc.title!)' has been selected")

        let currentLocMapItem = MKMapItem.mapItemForCurrentLocation()

        let selectedPlacemark = MKPlacemark(coordinate: selectedLoc.coordinate, addressDictionary: nil)
        let selectedMapItem = MKMapItem(placemark: selectedPlacemark)

        let mapItems = [selectedMapItem, currentLocMapItem]

        let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]

        MKMapItem.openMapsWithItems(mapItems, launchOptions:launchOptions)
}

1
不知怎么的,我甚至不知道就给这个答案点了踩(可能是有人拿着我的手机玩)。对此我深感抱歉。现在我无法撤销。如果您愿意,可以进行编辑,以便我可以恢复此操作。 - Vasil Garov
非常感谢你的帮助!我的最后一个问题是……我该如何将视图分配给在 performSearch() 中创建的注释?添加代码并运行后,注释视图仍然是默认的红色图钉。 - Alec
你不会直接调用 viewForAnnotation 方法,因为它是一个委托方法。地图视图会自动调用它。但是你在故事板中的地图视图的 delegate 出口必须连接到视图控制器。或者,在 viewDidLoad 中,执行 mapView.delegate = self 的代码。如果地图视图的委托没有设置,即使已经实现了委托方法,委托方法也不会被调用,地图视图将执行其默认操作。 - user467105
非常感谢您的帮助,一切都运行得很完美!我仍在学习过程中,很抱歉给您带来了这么多问题:D - Alec

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