Search code examples
uiviewcontrollerswift2mkmapviewmkannotationviewmkpointannotation

How to use callout button to open new uiviewcontroller. (Swift)


I have put several pins on my map for example corresponding to different bridge locations. Each of these pins have their own annotation when clicked on which displays their title and subtitle. I have added a info button within these annotations. However I do not know how to open a new UiViewController that will vary the information displayed on the UiViewController depending on which bridge info button is pressed.

so basically I need to know how to: 1: Open a UiViewController when the info button in the annotation is pressed. 2: Vary the information on the UiViewController spending on which of the bridges info buttons are pressed.

Here is what I have so far:

     mapView.delegate = self



    //bridges
    var Bridge1 = CLLocationCoordinate2DMake(48.60,2.90)
    var bridge2 = CLLocationCoordinate2DMake(48.61, 2.91)
    var bridge3 = CLLocationCoordinate2DMake(48.62, 2.92)
    var bridge4 = CLLocationCoordinate2DMake(48.63, 2.93)
    var bridge5 = CLLocationCoordinate2DMake(48.64, 2.94)
    var bridge6 = CLLocationCoordinate2DMake(48.65, 2.95)


    var span = MKCoordinateSpanMake(0.4, 0.4)
    var region = MKCoordinateRegion(center: Bridge1, span: span)
    mapView.setRegion(region, animated: true)

    var Bridge1pin = MKPointAnnotation()
    Bridge1pin.coordinate = Bridge1
    Bridge1pin.title = "Bridge1"
    Bridge1pin.subtitle = "This is bridge 1"
    mapView.addAnnotation(Bridge1pin)

    var bridge2pin = MKPointAnnotation()
    bridge2pin.coordinate = bridge2
    bridge2pin.title = "Bridge2"
    bridge2pin.subtitle = "This is bridge 2"
    mapView.addAnnotation(bridge2pin)

    var bridge3pin = MKPointAnnotation()
    bridge3pin.coordinate = bridge3
    bridge3pin.title = "Bridge3"
    bridge3pin.subtitle = "This is bridge 3"
    mapView.addAnnotation(bridge3pin)

    var bridge4pin = MKPointAnnotation()
    bridge4pin.coordinate = bridge4
    bridge4pin.title = "Bridge4"
    bridge4pin.subtitle = "This is bridge 4"
    mapView.addAnnotation(bridge4pin)

    var bridge5pin = MKPointAnnotation()
    bridge5pin.coordinate = bridge5
    bridge5pin.title = "bridge5"
    bridge5pin.subtitle = "hello this is bridge 5"
    mapView.addAnnotation(bridge5pin)

    var bridge6pin = MKPointAnnotation()
    bridge6pin.coordinate = bridge6
    bridge6pin.title = "bridge6"
    bridge6pin.subtitle = "hello this is bridge 6"
    mapView.addAnnotation(bridge6pin)




}


func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    let reuseIdentifier = "pin"
    var pin = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseIdentifier) as? MKPinAnnotationView
    if pin == nil {
        pin = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
        pin!.pinColor = .Red
        pin!.canShowCallout = true
        pin!.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
    } else {
        pin!.annotation = annotation
    }
    return pin
}


}

Solution

  • You can learn about navigation between the different views here in this link.

    And I will give some hint on the navigation and preparing the data for the navigation.

    1. Detecting when user clicks on the bridge

    For this you just need to implement one callout method called calloutAccessoryControlTapped as below.

    func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
        performSegueWithIdentifier("info", sender: view)
        // Above line of code is used for the segue operation between multiple MVCs.
    }
    

    2. You need add segue operation

    This can be done by control drag from your primary view to the detail view on story board and select as show in the popup and in the Attribute inspector add the identifier as info

    3. Prepare the model for the tapped bridge

    For this just override prepareForSegue method as follow.

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        //Just validating by checking the same identifier 
        if (segue.identifier == "info") {
            if let annotation = sender as? MKAnnotationView {
                let detailViewController = segue.destinationViewController as! DetailViewController
                detailViewController.titleText  = annotation.annotation?.title ?? ""
                detailViewController.detaileText = annotation.annotation?.subtitle ?? ""
            }
        }
    }
    

    4. Here is the DetailViewController.

    It just has two labels now just to display the title and subtitle.

    import UIKit
    class DetailViewController: UIViewController {
        @IBOutlet weak var titleLabel: UILabel!
        @IBOutlet weak var detailLabel: UILabel!
    
        var titleText: String? { didSet { updateUI() } }
        var detaileText: String? { didSet { updateUI() } }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            updateUI()
        }
    
        private func updateUI() {
            self.titleLabel?.text = self.titleText
            self.detailLabel?.text = self.detaileText
        }
    }