出队时 MapKit 注释视图标签在错误的注释中更改 position/showing

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

我正在我的地图图钉下方添加标签以显示图钉的一些细节。我通过添加一个 UILabel 作为 annotationView 的子视图并将其行数设置为 0 来实现这一点,以便在同一标签上显示多行。我遇到了一个问题,地图最初加载了正确的注释,我可以在地图图钉的标签中看到正确的数据,但是当我导航到另一个屏幕然后返回到地图时,地图图钉是都在正确的位置,但它们下面的标签不再显示标签中的正确数据,它们都混淆了。地图图钉开始显示属于其他地图图钉的数据。另外,如果我稍微移动地图然后回到同一个图钉,也会发生同样的事情。

我在 viewForAnnotation 方法中向标签添加数据:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
// Return the view marker different for editing items ie draggable undragrable.

    if ([annotation isKindOfClass:[PSMapAnnotation class]] == YES) {
        PSMapAnnotation *senderAnnotation = (PSMapAnnotation *)annotation;
        PSMapAnnotationView *annotationView = (PSMapAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:[senderAnnotation getPinKey]];

        if (annotationView == nil) {
            annotationView = [[PSMapAnnotationView alloc]
                              initWithAnnotation:senderAnnotation
                              reuseIdentifier:[senderAnnotation getPinKey]];
            



            // THIS LINE RETURNS A STRING ARRAY CONTAINING LABEL DATA

            NSMutableArray *taggedAnswers = [self _getTaggedAnswersForMarkerLabel:annotationView];
            

            annotationView.enabled = YES;
            annotationView.canShowCallout = NO;
            
            UILabel *annotationLabel = [[UILabel alloc] init];
            
            annotationLabel.text = @"";
            annotationLabel.numberOfLines = 0;
            annotationLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:14.0];
            annotationLabel.textColor = [UIColor blackColor];
            annotationLabel.textAlignment = NSTextAlignmentCenter;

            // LOOP THROUGH STRING ARRAY AND ADD ALL STRINGS TO ANNOTATION LABEL
            
            for (NSString* taggedAnswer in taggedAnswers)
            {
                
                NSString *textToShow = [NSString stringWithFormat: @"%@\n", taggedAnswer];

                annotationLabel.text = [annotationLabel.text stringByAppendingString: textToShow];

            }
            
            [annotationLabel sizeToFit];
            annotationLabel.center = CGPointMake(annotationView.center.x, annotationView.center.y);
            
            
            annotationView.myLabel = annotationLabel;
            [annotationView addSubview:annotationLabel];
            
            
            [annotationView setAnnotation:annotation];
            

        }
        else {
            
            [annotationView setAnnotation:annotation];
            
        }
        return annotationView;

配置注释视图的所有代码都在 if (annotationView == nil) { ... } 块中。所以,如果它成功地重用了一个注释视图(你的 else 块),你就没有设置标签。

您应该将 annotationLabel.text = ... 代码移到 if 语句之外。例如

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

例如

//  CustomAnnotationView.h

@import UIKit;
@import MapKit;

@interface CustomAnnotationView : MKPinAnnotationView
@end

//  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

产生:

根据您的需要清楚地自定义它,但希望它能说明这个想法。

注意使用约束以确保标签始终居中。

可能不用说了,这里我使用了注解的 title 属性,但是你可以检查你的注解子类并获取任何你想要的 属性,例如你的 textToShow。但是鉴于已经有一个 属性 用于将文本字符串与注释相关联,可以是 title(如果需要,也可以选择 subtitle),我会使用它。


您可能会考虑将标签的添加移动到 PSMapAnnotationView init 方法中,以便注释视图负责配置其子视图。您可以为 PSMapAnnotationView 覆盖 annotation 属性 的 setter 来为您设置标签文本。

这有以下好处:(a) 它简化了您的 MKMapViewDelegate 代码; (b) 将子视图配置保留在它所属的地方; (c) 如果仅支持 iOS 11 及更高版本,则为完全消除 viewForAnnotation 打开了大门。例如。在 viewDidLoad 中添加一行:

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

然后您可以完全删除 viewForAnnotation(除非您需要支持多种注释类型)。