Hi all,
In this Demo I will show How to implement Apple ‘s MapKit on iOS.
This demo will show following this.
1. Show Annotation in Maps.
2. Show Custom Annotation in Maps.
3. Show Custom Annotation with Custom Button in Maps.
4. Pin Point to location from Search.
5. Showing Route/Direction between two location in Maps.
We will jump into the code now..
Before this you should have linked your UI views..
I have a textfield and a MapView here along with other variables.
let regionRadius: CLLocationDistance = 1000; var option = 0; var directionsResponse : MKDirectionsResponse! var route : MKRoute! @IBOutlet weak var searchTF: UITextField! @IBOutlet weak var mapView: MKMapView!
For simply Showing the location on Maps.
func centerMapOnLocation(location: CLLocation) { //Running inside main queue just to compliment other methods that are below. dispatch_async(dispatch_get_main_queue()) { let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, self.regionRadius * 2.0, self.regionRadius * 2.0) self.mapView.setRegion(coordinateRegion, animated: true) } }
Now To show Annotation
You need to add the MapDelegate (MKMapViewDelegate) and implement the following method.
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? { if (annotation is MKUserLocation) { return nil } if (annotation.isKindOfClass(CustomAnnotation)) { let customAnnotation = annotation as? CustomAnnotation mapView.translatesAutoresizingMaskIntoConstraints = false var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier("CustomAnnotation") as MKAnnotationView! if (annotationView == nil) { annotationView = customAnnotation?.annotationView() } else { annotationView.annotation = annotation; } self.addBounceAnimationToView(annotationView) return annotationView } else { let reuseId = "test" var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) if anView == nil { anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId) anView!.image = UIImage(named:"flag_marker.png") anView!.canShowCallout = true } else { //we are re-using a view, update its annotation reference... anView!.annotation = annotation } return anView } } // For a simple Animation func addBounceAnimationToView(view: UIView) { let bounceAnimation = CAKeyframeAnimation(keyPath: "transform.scale") as CAKeyframeAnimation bounceAnimation.values = [ 0.05, 1.1, 0.9, 1] let timingFunctions = NSMutableArray(capacity: bounceAnimation.values!.count) for var i = 0; i < bounceAnimation.values!.count; i++ { timingFunctions.addObject(CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)) } bounceAnimation.timingFunctions = timingFunctions as NSArray as? [CAMediaTimingFunction] bounceAnimation.removedOnCompletion = false view.layer.addAnimation(bounceAnimation, forKey: "bounce") } // To Show Annotation func showAnnotation() { let newYorkLocation = CLLocationCoordinate2DMake(40.730872, -74.003066) // Drop a pin let dropPin = MKPointAnnotation() dropPin.coordinate = newYorkLocation dropPin.title = "New York City" mapView.addAnnotation(dropPin) let initialLocation = CLLocation(latitude: newYorkLocation.latitude, longitude: newYorkLocation.longitude) centerMapOnLocation(initialLocation) }
To Show a Custom Annotation, We need to extend MKAnnotation Class..
So Create a new Class and Name it CustomAnnotation.
import UIKit import MapKit class CustomAnnotation : NSObject, MKAnnotation { var coordinate: CLLocationCoordinate2D var title: String? var subtitle: String? var detailURL: NSURL var enableInfoButton : Bool init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, detailURL: NSURL, enableInfoButton : Bool) { self.coordinate = coordinate self.title = title self.subtitle = subtitle self.detailURL = detailURL self.enableInfoButton = enableInfoButton; } func annotationView() -> MKAnnotationView { let view = MKAnnotationView(annotation: self, reuseIdentifier: "CustomAnnotation") view.translatesAutoresizingMaskIntoConstraints = false view.enabled = true view.canShowCallout = true view.image = UIImage(named: "flag_marker") view.rightCalloutAccessoryView = UIButton(type: UIButtonType.Custom) view.centerOffset = CGPointMake(0, -32) if(self.enableInfoButton){ let deleteButton = UIButton(type: UIButtonType.System) as UIButton deleteButton.frame.size.width = 35 deleteButton.frame.size.height = 35 deleteButton.backgroundColor = UIColor.whiteColor() deleteButton.setImage(UIImage(named: "info"), forState: .Normal) deleteButton.addTarget(self, action: "infoClicked:", forControlEvents: .TouchUpInside) view.leftCalloutAccessoryView = deleteButton } return view } func infoClicked(sender: AnyObject?) { print("infoClicked") } }
To Show Custom Annotation
func showCustomAnnotation(location: CLLocation, title: String) { dispatch_async(dispatch_get_main_queue()) { let dropPin = CustomAnnotation(coordinate: location.coordinate, title: title, subtitle: title, detailURL: NSURL(string: "https://google.com")!, enableInfoButton : false) self.mapView.addAnnotation(dropPin) let initialLocation = CLLocation(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude) self.centerMapOnLocation(initialLocation) } } //OR func showCustomAnnotation() { let newYorkLocation = CLLocationCoordinate2DMake(40.730872, -74.003066) // Drop a pin let dropPin = CustomAnnotation(coordinate: newYorkLocation, title: "New York", subtitle: "New York Subtitle", detailURL: NSURL(string: "https://google.com")!, enableInfoButton : false) mapView.addAnnotation(dropPin) let initialLocation = CLLocation(latitude: newYorkLocation.latitude, longitude: newYorkLocation.longitude) centerMapOnLocation(initialLocation) }
To Show a Custom Annotation With Button
func showCustomAnnotationWithButton() { let newYorkLocation = CLLocationCoordinate2DMake(40.730872, -74.003066) // Drop a pin let dropPin = CustomAnnotation(coordinate: newYorkLocation, title: "New York", subtitle: "New York Subtitle", detailURL: NSURL(string: "https://google.com")!, enableInfoButton : true) mapView.addAnnotation(dropPin) let initialLocation = CLLocation(latitude: newYorkLocation.latitude, longitude: newYorkLocation.longitude) centerMapOnLocation(initialLocation) }
Search a Place and find the latitude and Longitude of that Place.
func setLatLong(place : String) { let geocoder: CLGeocoder = CLGeocoder() geocoder.geocodeAddressString(place, completionHandler: {(placemarks: [CLPlacemark]?, error: NSError?) -> Void in if (placemarks?.count > 0) { let topResult: CLPlacemark = (placemarks?[0])! let placemark: MKPlacemark = MKPlacemark(placemark: topResult) var region: MKCoordinateRegion = self.mapView.region region.center = (placemark.location?.coordinate)! region.span.longitudeDelta /= 8.0 region.span.latitudeDelta /= 8.0 self.mapView.setRegion(region, animated: true) self.mapView.addAnnotation(placemark) } }) }
To Find Directions between Two Pints in the Map…
func getDirections() { var source: MKMapItem! var destination : MKMapItem! let geoCoder = CLGeocoder() let addressString = "NewYork" geoCoder.geocodeAddressString(addressString, completionHandler: {(placemarks, error)->Void in if error != nil { print("Geocode failed with error: \(error?.localizedDescription)") } else if placemarks?.count > 0 { let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT dispatch_async(dispatch_get_global_queue(priority, 0)) { let placemark = placemarks![0]// as! CLPlacemark let location = placemark.location let addressDict = [String(CNPostalAddress): addressString as AnyObject] let startPlace = MKPlacemark(coordinate:location!.coordinate, addressDictionary: addressDict) self.showCustomAnnotation(location!, title: "Origin") source = MKMapItem(placemark: startPlace); let finalLocation = CLLocationCoordinate2DMake(40.700872, -74.003066) let place = MKPlacemark(coordinate: finalLocation, addressDictionary: addressDict) self.showCustomAnnotation( CLLocation(latitude: finalLocation.latitude, longitude: finalLocation.longitude), title: "Destination") destination = MKMapItem(placemark:place) print(location!.coordinate) let request:MKDirectionsRequest = MKDirectionsRequest() // source and destination are the relevant MKMapItems request.source = source; request.destination = destination; // Specify the transportation type request.transportType = MKDirectionsTransportType.Automobile; // If you're open to getting more than one route, // requestsAlternateRoutes = true; else requestsAlternateRoutes = false; request.requestsAlternateRoutes = true let directions = MKDirections(request: request) directions.calculateDirectionsWithCompletionHandler ({ (response: MKDirectionsResponse?, error: NSError?) in if error == nil { // Get whichever currentRoute you'd like, ex. 0 self.route = response!.routes[0] as MKRoute //move the camera to the region let coordinateRegion = MKCoordinateRegionMakeWithDistance(location!.coordinate, self.regionRadius * 2.0, self.regionRadius * 2.0) dispatch_async(dispatch_get_main_queue()) { self.mapView.setRegion(coordinateRegion, animated: true) print("Setting route"); //show the route self.mapView.addOverlay(self.route.polyline, level: MKOverlayLevel.AboveRoads) } }else{ print("ERROR Setting route %@", error?.description); } }) } } }) } func mapView(mapView : MKMapView , rendererForOverlay overlay: MKOverlay) ->MKOverlayRenderer { var polyLineRenderer : MKPolylineRenderer! if overlay is MKPolyline { polyLineRenderer = MKPolylineRenderer(overlay: overlay) polyLineRenderer.strokeColor = UIColor.redColor() polyLineRenderer.lineWidth = 3 } return polyLineRenderer }
You can download the complete iOS Source Code from here..