Vlad Pulichev
Vlad Pulichev

Reputation: 3272

How to add two or more buttons to annotationView: MKAnnotationView?

I want to have a MKAnnotationView to my pins on map (using MapKit) with next attributes:

1) image

2) details button

3) another details button

4) another details button?

I have done actually adding image and details button with next code:

annotationView.detailCalloutAccessoryView = snapshotView // snapshot view is a custom view
                                                         // with image and its constraints

let detailsButton = UIButton(type: .detailDisclosure)
annotationView.rightCalloutAccessoryView = detailsButton 

So, the question is how to add more than one button to MKAnnotationView?

Because all the tutorials that I've ever seen only is "how to add details button".

Upvotes: 3

Views: 2800

Answers (2)

Vlad Pulichev
Vlad Pulichev

Reputation: 3272

I have done it

From documentation left and right calloutAccessoryView are low width and height. So, we can add buttons and image only in detailCalloutAccessoryView.

Here is my code. It's working. I haven't done a review. Because it's more clear for understanding.

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
    if !(view.annotation! is MKUserLocation) {
        let customPin = view.annotation as! CustomPin
        self.spotDetailsForSendToPostsStripController = customPin.spotDetailsItem // its for sending to another controller.

        configureDetailView(annotationView: view, spotPin: customPin.spotDetailsItem)
    }
}

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation is MKUserLocation {
        return nil
    }

    if !(annotation is CustomPin) {
        return nil
    }

    let identifier = "CustomPin"

    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
    if annotationView == nil {
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        annotationView?.canShowCallout = true
    } else {
        annotationView!.annotation = annotation
    }

    return annotationView
}

func configureDetailView(annotationView: MKAnnotationView, spotPin: SpotDetailsItem) {
    let width = 250
    let height = 250

    let snapshotView = UIView()
    let views = ["snapshotView": snapshotView]
    snapshotView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[snapshotView(250)]", options: [], metrics: nil, views: views))
    snapshotView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[snapshotView(250)]", options: [], metrics: nil, views: views))

    let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height - 40))

    // configure button1
    let button1 = UIButton(frame: CGRect(x: 0, y: height - 35, width: width / 2 - 5, height: 35))
    button1.setTitle("Info", for: .normal)
    button1.backgroundColor = UIColor.darkGray
    button1.layer.cornerRadius = 5
    button1.layer.borderWidth = 1
    button1.layer.borderColor = UIColor.black.cgColor
    button1.addTarget(self, action: #selector(MainFormController.goToInfo), for: .touchDown)

    // configure button2
    let button2 = UIButton(frame: CGRect(x: width / 2 + 5, y: height - 35, width: width / 2, height: 35))
    button2.setTitle("Posts", for: .normal)
    button2.backgroundColor = UIColor.darkGray
    button2.layer.cornerRadius = 5
    button2.layer.borderWidth = 1
    button2.layer.borderColor = UIColor.black.cgColor
    button2.addTarget(self, action: #selector(MainFormController.goToPosts), for: .touchDown)

    // configure image
    let image = UIImage(contentsOfFile: "plus-512.gif")
    imageView.image = image // implement your own logic
    imageView.layer.cornerRadius = imageView.frame.size.height / 10
    imageView.layer.masksToBounds = true
    imageView.layer.borderWidth = 0
    imageView.contentMode = UIViewContentMode.scaleAspectFill

    // adding it to view
    snapshotView.addSubview(imageView)
    snapshotView.addSubview(button1)
    snapshotView.addSubview(button2)

    annotationView.detailCalloutAccessoryView = snapshotView
}

func goToPosts() {
    print("go to posts") // your implementation(segues and etc)
}

func goToInfo() {
    print("go to info") // your implementation(segues and etc)
}

CustomPin:

class CustomPin: MKPointAnnotation {
    var spotDetailsItem: SpotDetailsItem! // its my info of this place
}

Works like a charm

Result

Upvotes: 2

Oleg Gordiichuk
Oleg Gordiichuk

Reputation: 15512

You can use detailCalloutAccessoryView of the MKAnnotationView to achieve that.

Example how to do extension of the MKAnnotationView with UIStackView:

extension MKAnnotationView {

    func conteiner(arrangedSubviews: [UIView]) {
        let stackView = UIStackView(arrangedSubviews: arrangedSubviews)
        stackView.axis = .vertical
        stackView.distribution = .fillEqually
        stackView.alignment = .fill
        stackView.spacing = 5
        stackView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleLeftMargin, .flexibleBottomMargin, .flexibleWidth, .flexibleHeight]
        stackView.translatesAutoresizingMaskIntoConstraints = false

        self.detailCalloutAccessoryView = stackView
    }
}

And how to implement this:

extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

        let annotationIdentifier = "AnnotationIdentifier"

        var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier)

        if annotationView == nil {
            annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
            annotationView!.canShowCallout = true
            annotationView!.conteiner(arrangedSubviews: [UIButton(type: .detailDisclosure), UIButton(type: .detailDisclosure), UIButton(type: .detailDisclosure)])

        }
        else {
            annotationView!.annotation = annotation
        }

        return annotationView
    }
}

Result: enter image description here

Upvotes: 2

Related Questions