Searching Annotations in MapView

家住魔仙堡 提交于 2019-12-10 15:26:02

问题


I followed a how-to-search-for-location-using-apples-mapkit about searching annotations in mapView and its searching around the world with MKLocalSearch.

However, I don't want to to search with MKLocalSearch but search my own annotations i added myself like these for example:

let LitzmanLocation = CLLocationCoordinate2DMake(32.100668,34.775192)
        // Drop a pin
        let Litzman = MKPointAnnotation()
        Litzman.coordinate = LitzmanLocation
        Litzman.title = "Litzman Bar"
        Litzman.subtitle = "נמל תל אביב 18,תל אביב"
        mapView.addAnnotation(Litzman)

        let ShalvataLocation = CLLocationCoordinate2DMake(32.101145,34.775163)
        // Drop a pin
        let Shalvata = MKPointAnnotation()
        Shalvata.coordinate = ShalvataLocation
        Shalvata.title = "Shalvata"
        Shalvata.subtitle = "האנגר 28,נמל תל אביב"
        mapView.addAnnotation(Shalvata)


        let MarkidLocation = CLLocationCoordinate2DMake(32.074961,34.781679)
        // Drop a pin
        let Markid = MKPointAnnotation()
        Markid.coordinate = MarkidLocation
        Markid.title = "Markid"
        Markid.subtitle = "אבן גבירול 30,תל אביב"
        mapView.addAnnotation(Markid)

Here is my Code:

MapViewController.Swift:

import UIKit
import MapKit
import CoreLocation

protocol HandleMapSearch {
    func dropPinZoomIn(placemark:MKPlacemark)
}

class MapViewController: UIViewController,MKMapViewDelegate, CLLocationManagerDelegate,UISearchBarDelegate{


    @IBOutlet var mapView: MKMapView!

    var resultSearchController:UISearchController? = nil

    var selectedPin:MKPlacemark? = nil

    @IBAction func MapSearchController(sender: AnyObject) {
        resultSearchController!.hidesNavigationBarDuringPresentation = false
        self.resultSearchController!.searchBar.delegate = self
        presentViewController(resultSearchController!, animated: true, completion: nil)
        self.resultSearchController!.searchBar.barTintColor = UIColor.blackColor()
        self.resultSearchController!.searchBar.placeholder = "חפש ברים"
        self.resultSearchController!.dimsBackgroundDuringPresentation = true
        self.resultSearchController!.searchBar.sizeToFit()
    }
override func viewDidLoad() {
        super.viewDidLoad()

        let locationSearchTable = storyboard!.instantiateViewControllerWithIdentifier("LocationSearchTable") as! LocationSearchTable
        resultSearchController = UISearchController(searchResultsController: locationSearchTable)
        resultSearchController?.searchResultsUpdater = locationSearchTable

        locationSearchTable.mapView = mapView

        locationSearchTable.handleMapSearchDelegate = self
}
}
}

extension MapViewController: HandleMapSearch {
    func dropPinZoomIn(placemark:MKPlacemark){
        // cache the pin
        selectedPin = placemark
        // clear existing pins
        mapView.removeAnnotations(mapView.annotations)
        let annotation = MKPointAnnotation()
        annotation.coordinate = placemark.coordinate
        annotation.title = placemark.name
        if let city = placemark.locality,
            let state = placemark.administrativeArea {
            annotation.subtitle = "(city) (state)"
        }
        mapView.addAnnotation(annotation)
        let span = MKCoordinateSpanMake(0.05, 0.05)
        let region = MKCoordinateRegionMake(placemark.coordinate, span)
        mapView.setRegion(region, animated: true)
    }
}

LocalSearchTable.Swift:

import UIKit
import MapKit

class LocationSearchTable : UITableViewController {

    var matchingItems:[MKMapItem] = []
    var mapView: MKMapView? = nil

    var handleMapSearchDelegate:HandleMapSearch? = nil

    func parseAddress(selectedItem:MKPlacemark) -> String {
        // put a space between "4" and "Melrose Place"
        let firstSpace = (selectedItem.subThoroughfare != nil && selectedItem.thoroughfare != nil) ? " " : ""
        // put a comma between street and city/state
        let comma = (selectedItem.subThoroughfare != nil || selectedItem.thoroughfare != nil) && (selectedItem.subAdministrativeArea != nil || selectedItem.administrativeArea != nil) ? ", " : ""
        // put a space between "Washington" and "DC"
        let secondSpace = (selectedItem.subAdministrativeArea != nil && selectedItem.administrativeArea != nil) ? " " : ""
        let addressLine = String(
            format:"%@%@%@%@%@%@%@",
            // street number
            selectedItem.subThoroughfare ?? "",
            firstSpace,
            // street name
            selectedItem.thoroughfare ?? "",
            comma,
            // city
            selectedItem.locality ?? "",
            secondSpace,
            // state
            selectedItem.administrativeArea ?? ""
        )
        return addressLine
    }

    }

extension LocationSearchTable : UISearchResultsUpdating {
    func updateSearchResultsForSearchController(searchController: UISearchController) {
        guard let mapView = mapView,
            let searchBarText = searchController.searchBar.text else { return }
        let request = MKLocalSearchRequest()
        request.naturalLanguageQuery = searchBarText
        request.region = mapView.region
        let search = MKLocalSearch(request: request)
        search.startWithCompletionHandler { response, _ in
            guard let response = response else {
                return
            }
            self.matchingItems = response.mapItems
            self.tableView.reloadData()
        }
    }

}

extension LocationSearchTable {
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return matchingItems.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("MapSearchCell")!
        let selectedItem = matchingItems[indexPath.row].placemark
        cell.textLabel?.text = selectedItem.name
        cell.detailTextLabel?.text = parseAddress(selectedItem)
        return cell
    }
}

extension LocationSearchTable {
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let selectedItem = matchingItems[indexPath.row].placemark
        handleMapSearchDelegate?.dropPinZoomIn(selectedItem)
        dismissViewControllerAnimated(true, completion: nil)
    }
}

回答1:


you just refer to this link http://www.coderzheaven.com/2016/02/14/mapkit-demo-swift-annotation-custom-annotation-custom-annotation-with-button-search-showing-directions-apple-maps-ios/

you will understand the following topics

  • Show Annotation in Maps.
  • Show Custom Annotation in Maps.
  • Show Custom Annotation with Custom Button in Maps.



回答2:


TL;DR

Example project: https://github.com/JakubMazur/SO40539590


Ok, so for the beginning I will suggest you separate data from your controller code. I choose json format as most universal one. So:

[
   {
      "title":"Litzman Bar",
      "subtitle":"נמל תל אביב 18,תל אביב",
      "coordinates":{
         "lat":32.100668,
         "lon":34.775192
      }
   },
   {
      "title":"Shalvata",
      "subtitle":"האנגר 28,נמל תל אביב",
      "coordinates":{
         "lat":32.101145,
         "lon":34.775163
      }
   },
   {
      "title":"Markid",
      "subtitle":"אבן גבירול 30,תל אביב",
      "coordinates":{
         "lat":32.074961,
         "lon":34.781679
      }
   }
]

This is basically your database.

Now let's parse it into an Array to use inside your ViewConttroller. Again I will suggest you split it into Model objects like Location and Coordinate. Let's have a look in one class of it as example:

class Location: NSObject {

    var title : String = String()
    var subtitle : String = String()
    var coordinates : Coordinate = Coordinate()

    public class func locationFromDictionary(_ dictionary : Dictionary<String, AnyObject>) -> Location {
        let location : Location = Location()
        location.title = dictionary["title"] as! String
        location.subtitle = dictionary["subtitle"] as! String
        location.coordinates = Coordinate.coordinateFromDictionary(dictionary["coordinates"] as! Dictionary<String, AnyObject>)
        return location;
    }
}

I will not paste the code for parsing json file to this objects, because that's what is not this question is about. You will find in into repository.

And now let's focus on question.

I will recommend you not to search annotations, but search your data model and redraw annotations when needed

In order to do that (i will use UISearchBar for it):

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    self.displayArray = self.locationsDatabase.filter() {
        return $0.title.contains("i")
    }

Then when you ovverride a setter like this:

var displayArray : Array<Location> = [] {
    didSet {
        self.mapView .removeAnnotations(self.mapView.annotations)
        for location in displayArray {
            let coords : Coordinate = location.coordinates
            let point = MKPointAnnotation()
            point.coordinate = CLLocationCoordinate2DMake(CLLocationDegrees(coords.latitude),CLLocationDegrees(coords.longitude))
            point.title = location.title
            point.subtitle = location.subtitle
            mapView.addAnnotation(point)
        }
    }
}

You can redraw your annotations. The edge cases like empty search field, case sensivity, dismissing keyboard I leave to you. But hope you will get the general idea. You may think that it's overengineered but having objects as a separate classes and universal format as an data input may benefit in the future.

Full project: https://github.com/JakubMazur/SO40539590



来源:https://stackoverflow.com/questions/40539590/searching-annotations-in-mapview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!