Search code examples
swiftmapsmkmapviewmkannotation

Swift: Add Directions button to pin annotation


I have an app that displays the company location using an MKMapView. When the user visits the contact page a map appears at the top of the screen where a pin drops and it shows our location. When the map pin is clicked it shows the company name in the annotation.

I am pulling the company address into the MKMApView from data stored in my Parse backend using back4app.

I have this all working perfectly, however, when I click the map pin and it shows the company name, I am trying to get a car icon button in there also so the user can get directions to our company.

Here is the code I have to set the annotation:

func addPinOnMap(_ address: String) {
    var hotelClass = PFObject(className: HOTEL_CLASS_NAME)
    hotelClass = hotelArray[0]

    if mapView.annotations.count != 0 {
        annotation = mapView.annotations[0] 
        mapView.removeAnnotation(annotation)
    }

    // Make a search on the Map
    localSearchRequest = MKLocalSearchRequest()
    localSearchRequest.naturalLanguageQuery = address
    localSearch = MKLocalSearch(request: localSearchRequest)

    localSearch.start { (localSearchResponse, error) -> Void in

        // Add PointAnnonation text and a Pin to the Map
        self.pointAnnotation = MKPointAnnotation()
        self.pointAnnotation.title = "\(hotelClass[HOTEL_NAME]!)"
        self.pointAnnotation.coordinate = CLLocationCoordinate2D( latitude: localSearchResponse!.boundingRegion.center.latitude, longitude:localSearchResponse!.boundingRegion.center.longitude)

        self.pinView = MKPinAnnotationView(annotation: self.pointAnnotation, reuseIdentifier: nil)
        self.mapView.centerCoordinate = self.pointAnnotation.coordinate
        self.mapView.addAnnotation(self.pinView.annotation!)

        // Zoom the Map to the location
        self.region = MKCoordinateRegionMakeWithDistance(self.pointAnnotation.coordinate, 1000, 1000);
        self.mapView.setRegion(self.region, animated: true)
        self.mapView.regionThatFits(self.region)
        self.mapView.reloadInputViews()
    }

}

I simply do not know how I can get the button icon in the annotation and show directions upon click of the button. either using the current map view or to open the users maps app on their device, either way is fine.

Thank you.


Solution

  • I propose you a sample method to had a button on your pin and to give to the user the direction of the pin with the apple map app.

    First, after your pin's declaration, you should declare a button witch give you the opportunity to interact with the user in the pin (we will show later how to initialize the button in the pin).

    You can declare your button like this:

    let smallSquare = CGSize(width: 30, height: 30)
    let button = UIButton(frame: CGRect(origin: CGPointZero, size: smallSquare))
    

    Note, smallSquare give to the button the correct size of your future pin's button.


    You can add a image in the pin's button with the method: button.setBackgroundImage(UIImage(named: "car"), forState: .Normal).

    Apple developer give to us some documentation: Apple developer web site.


    Then you can had a button action with this method: button.addTarget(self, action: #selector(ViewController.getDirections), forControlEvents: .TouchUpInside). So, like this, if the button is selected normally (.TouchUpInside), the program calls the function getDirection ().


    Now, you can initialize the button in your pin with the method: pinView?.leftCalloutAccessoryView = button.

    Note this method set the button in the left of the pin. You can put the button in the right like this: pinView?.rightCalloutAccessoryView = button.

    Apple developer give some informations on the subject.

    However, I do not know how to initialize the button in the totally surface of the pin.


    Finally, you should have the function getDirections ()to give to the user the "direction" of the pin.

    I propose you to use the apple map app for this purpose.

    My function getDirections () look like this:

    func getDirections(){
            guard let selectedPin = selectedPin else { return }
            let mapItem = MKMapItem(placemark: selectedPin)
            let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
            mapItem.openInMapsWithLaunchOptions(launchOptions)
    
            print ("GET DIRECTION")
        }
    

    I find this function in this web site. I think it can be explain this better than me.

    At the end my program looks like this:

    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView?{
    
        guard !(annotation is MKUserLocation) else { return nil }
        let reuseId = "pin"
        var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
        if pinView == nil {
            pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        }
        pinView?.pinTintColor = UIColor.orangeColor()
        pinView?.canShowCallout = true
        //The initialization of the pin. Here your program looks great.
    
        // And after the code as seen above.
        let smallSquare = CGSize(width: 30, height: 30)
        let button = UIButton(frame: CGRect(origin: CGPointZero, size: smallSquare))
        button.setBackgroundImage(UIImage(named: "car"), forState: .Normal)
        button.addTarget(self, action: #selector(ViewController.getDirections), forControlEvents: .TouchUpInside)
        pinView?.leftCalloutAccessoryView = button
    
         return pinView
    }
    
    
    
    
    func getDirections(){
        guard let selectedPin = selectedPin else { return }
        let mapItem = MKMapItem(placemark: selectedPin)
        let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
        mapItem.openInMapsWithLaunchOptions(launchOptions)
    
        print ("GET DIRECTION")
    }
    

    Normally, your program should look like this:

     func addPinOnMap(_ address: String) {    
    
            var hotelClass = PFObject(className: HOTEL_CLASS_NAME)
            hotelClass = hotelArray[0]
    
            if mapView.annotations.count != 0 {
                annotation = mapView.annotations[0]
                mapView.removeAnnotation(annotation)
            }
    
            // Make a search on the Map
            localSearchRequest = MKLocalSearchRequest()
            localSearchRequest.naturalLanguageQuery = address
            localSearch = MKLocalSearch(request: localSearchRequest)
    
            localSearch.start { (localSearchResponse, error) -> Void in
    
                // Add PointAnnonation text and a Pin to the Map
                self.pointAnnotation = MKPointAnnotation()
                self.pointAnnotation.title = "\(hotelClass[HOTEL_NAME]!)"
                self.pointAnnotation.coordinate = CLLocationCoordinate2D( latitude: localSearchResponse!.boundingRegion.center.latitude, longitude:localSearchResponse!.boundingRegion.center.longitude)
    
                self.pinView = MKPinAnnotationView(annotation: self.pointAnnotation, reuseIdentifier: nil)
                self.mapView.centerCoordinate = self.pointAnnotation.coordinate
                self.mapView.addAnnotation(self.pinView.annotation!)
    
                let smallSquare = CGSize(width: 30, height: 30)
                let button = UIButton(frame: CGRect(origin: CGPointZero, size: smallSquare))
                button.setBackgroundImage(UIImage(named: "car"), forState: .Normal)
                button.addTarget(self, action: #selector(ViewController.getDirections), forControlEvents: .TouchUpInside)
                self.pinView?.leftCalloutAccessoryView = button
    
                // Zoom the Map to the location
                self.region = MKCoordinateRegionMakeWithDistance(self.pointAnnotation.coordinate, 1000, 1000);
                self.mapView.setRegion(self.region, animated: true)
                self.mapView.regionThatFits(self.region)
                self.mapView.reloadInputViews()
            }
    
    func getDirections(){
    guard let selectedPin = selectedPin else { return }
    let mapItem = MKMapItem(placemark: selectedPin)
    let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
    mapItem.openInMapsWithLaunchOptions(launchOptions)
    
    print ("GET DIRECTION")
    }
    

    Excuse me, I can not try your code because I have not your totally code like the pinView declaration.

    Note, you can need to add this line of code to accept than the pin can show callout pinView?.canShowCallout = true.

    You can consult this webs sites if you want more details or tell me a comment.

    Thorn technologies

    Apple developer