Reputation: 463
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:
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)
}
}
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)
}
}
Upvotes: 5
Views: 2241
Reputation: 358
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
Upvotes: 2
Reputation: 13860
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
Upvotes: 0