1

I have a custom annotation view, when I click on any annotation point, I can see the custom view with all information. but what I need is to see name of each industrial parks under each annotation points. now I can see only point but without names I need to see name under points.enter image description here

//MARK: MKMapViewDelegate
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    
    if annotation is MKUserLocation
    {
        return nil
    }
    var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: "Pin")
    if annotationView == nil{
        annotationView = AnnotationView(annotation: annotation, reuseIdentifier: "Pin")
        annotationView?.canShowCallout = false
    }else{
        annotationView?.annotation = annotation
    }
    annotationView?.image = UIImage(named: "test3a")
    
    return annotationView
}

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView)
{
    // 1
    if view.annotation is MKUserLocation
    {
        // Don't proceed with custom callout
        return
    }
    // 2
    let starbucksAnnotation = view.annotation as! StarbucksAnnotation
    let views = Bundle.main.loadNibNamed("CustomCalloutView", owner: nil, options: nil)
    let calloutView = views?[0] as! CustomCalloutView
    calloutView.starbucksName.text = starbucksAnnotation.name
    calloutView.starbucksAddress.text = starbucksAnnotation.address
    calloutView.starbucksPhone.text = starbucksAnnotation.phone
    
    //
    let button = UIButton(frame: calloutView.starbucksPhone.frame)
    button.addTarget(self, action: #selector(CellViewController.callPhoneNumber(sender:)), for: .touchUpInside)
    calloutView.addSubview(button)
    calloutView.starbucksImage.image = starbucksAnnotation.image
    // 3
    calloutView.center = CGPoint(x: view.bounds.size.width / 2, y: -calloutView.bounds.size.height*0.52)
    view.addSubview(calloutView)
    mapView.setCenter((view.annotation?.coordinate)!, animated: true)
}

func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
    if view.isKind(of: AnnotationView.self)
    {
        for subview in view.subviews
        {
            subview.removeFromSuperview()
        }
    }
}
  • For custom annotations I think you have to use the text bubble call-out that appears when you tap the annotation. – Magnas Aug 07 '21 at 06:32
  • @Magnas No, that’s not correct. – Rob Aug 07 '21 at 14:44
  • Sergej, are you talking about where this `calloutView` appears? I am assuming you must be, because why else would you have shared all of this custom callout code. With its custom placement. But `CGPoint(x: view.bounds.size.width / 2, y: -calloutView.bounds.size.height*0.52)` isn’t below the annotation, so that doesn’t make sense either. (BTW, add subview before you change the `center`.) Please clarify your question. – Rob Aug 07 '21 at 14:49
  • Bottom line, are you talking about where this callout is placed? Or are you talking about wanting to add another `UILabel`? And is that label present all the time, or just when the callout is presented? – Rob Aug 07 '21 at 14:51
  • What class does your annotationView extend? You get the title under your annotationViews for free if you use or extend `MKMarkerAnnotationView`. – Gerd Castan Aug 07 '21 at 22:22
  • @Rob : I have map view with custom annotation point, when I clicked on any annotation , new custom view with picture, name and description appear, that's OK. But I need to have under each annotation point the name, cause when you look at the map you see only point but without name, name is possible to see only when you clicked on any annotation point – Sergej Strajnak Aug 08 '21 at 10:04
  • Then I would suggest you remove all of this code related to selecting/deselecting the annotation view which shows/hides your custom callout, as that's not relevant to the question of having labels show up under all the annotation views. It's a bit misleading and confusing. – Rob Aug 08 '21 at 17:41
  • FWIW, in addition to adding label under the annotation view (like `MKMarkerAnnotationView` does or my custom annotation view below), you might consider turning on clustering (e.g. as outlined [here](https://stackoverflow.com/a/58657960/1271826) or [here](https://stackoverflow.com/a/60808603/1271826) or, if you want custom clustering annotation, [here](https://stackoverflow.com/a/56318257/12718260)). You have so many annotations here that adding a label underneath each is just going to make it even more cluttered. Clustering will solve that. – Rob Aug 08 '21 at 19:29

1 Answers1

0

If your goal is to have a label under the annotation, just have your custom annotation add this subview (and have it observe changes to the title so that it can update the label).

For example:

class AnnotationView: MKAnnotationView {
    static var image: UIImage = ...

    private var titleObserver: NSObjectProtocol!
    private let titleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.backgroundColor = UIColor.black.withAlphaComponent(0.25)
        label.font = UIFont.preferredFont(forTextStyle: .caption1)
        return label
    }()

    override var annotation: MKAnnotation? {
        didSet { updateForNewAnnotation() }
    }

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        image = Self.image
        centerOffset = CGPoint(x: 0, y: -Self.image.size.height / 2)

        configureTitleView()
        updateForNewAnnotation()
    }

    func configureTitleView() {
        addSubview(titleLabel)
        NSLayoutConstraint.activate([
            titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
            titleLabel.topAnchor.constraint(equalTo: bottomAnchor)
        ])
        clipsToBounds = false
    }

    func updateForNewAnnotation() {
        guard let annotation = annotation as? MKPointAnnotation else { // replace `MKPointAnnotation` with whatever class your annotations are
            titleObserver = nil
            titleLabel.text = nil
            return
        }

        titleLabel.text = annotation.title
        titleObserver = annotation.observe(\.title) { [weak self] annotation, _ in
            self?.titleLabel.text = annotation.title
        }
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}

That yields:

enter image description here

Obviously, feel free to configure your label however you want, but this illustrates the basic idea of adding subview and observing changes on the annotation’s title.


As an aside, notice that I set the image inside the AnnotationView class. If you keep all configuration inside the AnnotationView class, not only is it a better separation of responsibilities, but you can then retire mapView(_:viewFor:) entirely, and replace it with a single line inside your viewDidLoad that registers the annotation view class with register(_:forAnnotationViewWithReuseIdentifier:):

mapView.register(AnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
Rob
  • 415,655
  • 72
  • 787
  • 1,044