MapKit Demo Swift – Annotation, Custom Annotation, Custom Annotation with Button, Search, Showing Directions – Apple Maps iOS

By | February 14, 2016

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.

 

MapKit Demo iOs Apple 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..

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *