Reputation: 3272
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
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
Upvotes: 2
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
}
}
Upvotes: 2