MapKit iOS 9 detailCalloutAccessoryView usage

2019-01-17 12:04发布

After watching WWDC video 206 I assumed this would be a trivial task of adding the detail callout view to a mapView annotation view.

So, I assume Im doing something wrong.

With my pin view set up

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

    let view:MKAnnotationView!

    if let dequed = routeMapView.dequeueReusableAnnotationViewWithIdentifier("pin") {
        view = dequed
    }
    else {
        view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
    }

    let x = UIView(frame: CGRectMake(0, 0, 200, 200))
    x.backgroundColor = UIColor.redColor()

    // shows the red
    //view.leftCalloutAccessoryView = x

    // working as no subtitle - but no red view
    view.detailCalloutAccessoryView = x

    view.canShowCallout = true
    return view
}

I only get this

enter image description here

I know the view is working, because if I try it with the leftCalloutAccessoryView I get enter image description here

I must be missing something. Note, if I just add an image to the detailCalloutAccessoryView like

view.detailCalloutAccessoryView = UIImage(named:"YourImageName")

The image is there, size correctly etc

I just cannot figure out how to put in my own custom view.

Thanks

4条回答
Summer. ? 凉城
2楼-- · 2019-01-17 12:10

Use UIImageView

view.detailCalloutAccessoryView = UIImageView(image:UIImage(named:"YourImageName")) 
查看更多
劳资没心,怎么记你
3楼-- · 2019-01-17 12:14

You have to add some constraints for width and height of your view:

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    var av = mapView.dequeueReusableAnnotationViewWithIdentifier("id")
    if av == nil {
        av = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "id")
    }

    let myView = UIView()
    myView.backgroundColor = .greenColor()

    let widthConstraint = NSLayoutConstraint(item: myView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 40)
    myView.addConstraint(widthConstraint)

    let heightConstraint = NSLayoutConstraint(item: myView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 20)
    myView.addConstraint(heightConstraint)

    av!.detailCalloutAccessoryView = myView
    av!.canShowCallout = true

    return av!
}

Munich 1972

Adding an intrinsicContentSize also works.

I did some testing and found out, that MapKit automagically sets translatesAutoresizingMaskIntoConstraints to false, when you set a view to detailCalloutAccessoryView.

In the WWDC 2015 session "What's New in MapKit" it was told, that "auto layout is supported". I reckon that Apple really means, that you have to use auto layout?!

查看更多
劫难
4楼-- · 2019-01-17 12:28

1. Create a UIView and add it to yours maps VC in the Storyboard

enter image description here

Here you can set the size, constraints, add buttons, images, etc - layout how you want. Stack views work perfect in this instance.

2. Create and outlet to your Maps VC

Control drag as per usual, from your custom view.

@IBOutlet var customDetailView: UIView!

3. Set the detailCalloutAccessoryView for your pin

For example

func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
    view.detailCalloutAccessoryView = customDetailView
}

Success

enter image description here

查看更多
Fickle 薄情
5楼-- · 2019-01-17 12:32

You can use a custom class and override intrinsicContentSize to dynamically size the detail view dependent on its childrens content. (as hinted at by @Klaas in the accepted answer)

This may be especially helpful, if the size of your view is not known beforehand or does change during runtime or you simply do not want to add constraints programmatically.

Here is an example using two labels which are inside a stack view. The intrinsicContentSize is set to equal the size the stack view would take. Setting an instance of the following as the detailAccessoryView should get you a view that reacts to change in the labels text and needs no programmatically added constraints.

class CustomCalloutDetailView : UIView {

    @IBOutlet weak var label1: UILabel!

    @IBOutlet weak var label2: UILabel!

    @IBOutlet weak var mainStack: UIStackView!

    override var intrinsicContentSize: CGSize {
        get {
            return mainStack.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
        }
    }

    public func setLabel1(_ labelText: String) {
        self.label1.text = labelText
        self.invalidateIntrinsicContentSize()
    }
}
查看更多
登录 后发表回答