出队时 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
(除非您需要支持多种注释类型)。
我正在我的地图图钉下方添加标签以显示图钉的一些细节。我通过添加一个 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
(除非您需要支持多种注释类型)。