How to add two or more buttons to annotationView:

2019-02-18 18:45发布

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".

2条回答
We Are One
2楼-- · 2019-02-18 19:00

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

查看更多
太酷不给撩
3楼-- · 2019-02-18 19:15

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

查看更多
登录 后发表回答