Reputation: 463
In my project i have a mapView with a lot of annotations & i would like to add a search functionality to the map so i can search those annotations and quickly find the annotation i want.
I followed a tutorial i found on the web but it searches globally (MKLocalSearch) and not the annotations.
I tried looking for a tutorial \ Help for my problem but i couldn't get any help for a long time now. Here is my search code :
I've made these annotations :
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)
MapViewController:
//All my Map code is here
}
}
}
extension MapViewController: HandleMapSearch {
func dropPinZoomIn(placemark:MKPlacemark){
// cache the pin
selectedPin = placemark
// clear existing pins
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
annotation.title = placemark.name
if let _ = placemark.locality,
let _ = placemark.administrativeArea {
annotation.subtitle = ""
}
mapView.addAnnotation(annotation)
let span = MKCoordinateSpanMake(0.01, 0.01)
let region = MKCoordinateRegionMake(placemark.coordinate, span)
mapView.setRegion(region, animated: true)
}
}
SearchTable:
import UIKit
import MapKit
class LocationSearchTable : UITableViewController {
var matchingItems = [CustomAnnotations]()
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
}
func search(keywords:String) {
self.matchingItems.removeAll()
for annotation in self.mapView!.annotations {
if annotation.isKindOfClass(CustomAnnotations) {
//Just an example here for searching annotation by title, you could add other filtering actions else.
if (annotation.title??.rangeOfString(keywords) != nil) {
self.matchingItems.append(annotation as! CustomAnnotations)
}
}
}
self.tableView.reloadData()
}
}
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", forIndexPath: indexPath)
let selectedItem = matchingItems[indexPath.row]
cell.textLabel?.text = selectedItem.title
cell.detailTextLabel?.text = selectedItem.subtitle
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)
}
}
My question is how i can turn this to only search my annotations and not search all over the world with MKLocalSearch.
using swift 3 and Xcode 8
Thanks you for helping.
Upvotes: 0
Views: 597
Reputation: 104
If I’m reading this correctly, you just want to search annotations rather than all MapKit items. You could update the code in updateSearchResults to search the mapView.annotations array and filter your results (matchingItems) based on what’s in the search controller’s searchbar.
func updateSearchResults(for searchController: UISearchController) {
matchingItems = []
guard let mapView = mapView,
let searchBarText = searchController.searchBar.text else { return }
for item in self.mapView!.annotations {
let title = item.title! as! String
if title.hasPrefix(searchBarText) && searchBarText != "" {
matchingItems.append(item)
}
}
self.tableView.reloadData()
}
I wrote a quick test app and posted it https://github.com/hellzkitchen/stackoverflow-041917. In my example, I passed the selected annotation to handleMapSearch delegate method and just updated the mapView to center on it. Hope this helps.
Upvotes: 3