MapKit annotation view labels changing position/showing in wrong annotation when dequeued

All of your code for configuring the annotation view is inside the if (annotationView == nil) { ... } block. So, if it successfully reused an annotation view (your else block), you’re not setting the label.

You should move the annotationLabel.text = ... code outside of this if statement. E.g.

if (annotationView == nil) {
     // instantiate annotation view and add subview, but don’t set the `text` of the label yet
} else {
     annotationView.annotation = annotation;
}

annotationView.annotationLabel.text = ...

For example

//  CustomAnnotationView.h

@import UIKit;
@import MapKit;

@interface CustomAnnotationView : MKPinAnnotationView
@end

And

//  CustomAnnotationView.m

#import "CustomAnnotationView.h"

@interface CustomAnnotationView ()
@property (nonatomic) UILabel *label;
@end

@implementation CustomAnnotationView

- (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    if (self) {
        self.enabled = YES;
        self.canShowCallout = NO;

        self.label = [[UILabel alloc] init];
        self.label.translatesAutoresizingMaskIntoConstraints = false;
        self.label.text = @"";
        self.label.numberOfLines = 0;
        self.label.font = [UIFont fontWithName:@"HelveticaNeue" size:14.0];
        self.label.textColor = [UIColor labelColor];
        self.label.textAlignment = NSTextAlignmentCenter;
        [self addSubview:self.label];

        [NSLayoutConstraint activateConstraints:@[
            [self.label.topAnchor constraintEqualToAnchor:self.bottomAnchor constant:8],
            [self.label.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:-self.centerOffset.x]
        ]];

        [self updateForAnnotation:annotation];
    }

    return self;
}

- (void)setAnnotation:(id<MKAnnotation>)annotation {
    [super setAnnotation:annotation];
    [self updateForAnnotation:annotation];
}

- (void)updateForAnnotation:(id<MKAnnotation>)annotation {
    self.label.text = annotation.title;
}

@end

That yields:

enter image description here

Clearly customize this as you see fit, but hopefully it illustrates the idea.

Note the use of constraints to make sure that the label is always centered.

Probably needless to say, here I am using the title property of the annotation, but you could check for your annotation subclass and grab whatever property you want, e.g. your textToShow. But given that there is already a property for associating a text string with an annotation, either title (and optionally subtitle, if you need it), I would use that.


You might consider moving the adding of the label into the PSMapAnnotationView init method, so the annotation view takes care of configuring its subviews. And you can override the setter of the annotation property for PSMapAnnotationView to set the label text for you.

This has the benefit of (a) it simplifies your MKMapViewDelegate code; (b) keeps subview configuration where it belongs; and (c) opens up the door for completely eliminating viewForAnnotation if only supporting iOS 11 and later. E.g. in viewDidLoad add a line that says:

[self.mapView registerClass:[CustomAnnotationView class] forAnnotationViewWithReuseIdentifier:MKMapViewDefaultAnnotationViewReuseIdentifier];

And then you can remove viewForAnnotation entirely (unless you need support for multiple annotation types).

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top