如何显示通过plist加载的多个自定义注释(pin和左侧图标)?

将这个代码在工作时显示自定义的引脚和标志,或只是1针自定义标志? 请看下面的plist,只有错误是mapView的本地声明隐藏了实例variables。

<plist version="1.0"> <array> <dict> <key>stationIdKey</key> <string>BP</string> <key>stationNameKey</key> <string>Atkinson Dam Cabin Village</string> <key>stationAddressKey</key> <string>Atkinson Dam Road, Atkinson Dam</string> <key>stationLatitudeKey</key> <string>-27.415056</string> <key>stationLongitudeKey</key> <string>152.43057</string> </dict> <dict> <key>stationIdKey</key> <string>Shell</string> <key>stationNameKey</key> <string>BP - AYR DCA</string> <key>stationAddressKey</key> <string>108 Edwards Street, AYR</string> <key>stationLatitudeKey</key> <string>-19.57094107</string> <key>stationLongitudeKey</key> <string>147.4025662</string> </dict> 

和mapViewController.m文件

 - (void)viewDidload { [super viewDidLoad]; NSString *path = [[NSBundle mainBundle] pathForResource:@"stations" ofType:@"plist"]; NSArray *anns = [NSArray arrayWithContentsOfFile:path]; NSLog(@"anns=%@",anns); for(NSMutableDictionary *note in anns) { float realLatitude = [[note objectForKey:@"stationLatitudeKey"] floatValue]; float realLongitude = [[note objectForKey:@"stationLongitudeKey"] floatValue]; MyAnnotation* myAnnotation = [[MyAnnotation alloc] init]; CLLocationCoordinate2D theCoordinate; theCoordinate.latitude = realLatitude; theCoordinate.longitude = realLongitude; myAnnotation.coordinate = theCoordinate; myAnnotation.title = [note objectForKey:@"stationNameKey"]; myAnnotation.subtitle = [note objectForKey:@"stationAddressKey"]; myAnnotation.stationIdKey = [note objectForKey:@"stationIdKey"]; [mapView setDelegate:self]; [mapView addAnnotation:myAnnotation]; [myAnnotation release]; } } -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { if ([annotation isKindOfClass:[MyAnnotation class]]) { static NSString *reuseId = @"customAnn"; MKAnnotationView *customAnnotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId]; if (customAnnotationView == nil) { customAnnotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId] autorelease]; UIImage *pinImage = [UIImage imageNamed:@"pin-green.png"]; [customAnnotationView setImage:pinImage]; customAnnotationView.canShowCallout = YES; UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; customAnnotationView.rightCalloutAccessoryView = rightButton; } NSString *iconFilename = @""; MyAnnotation *myAnn = (MyAnnotation *)annotation; if ([myAnn.stationIdKey isEqualToString:@"BP"]) iconFilename = @"bp-logo.png"; else if ([myAnn.stationIdKey isEqualToString:@"Caltex"]) iconFilename = @"caltex.png"; else if ([myAnn.stationIdKey isEqualToString:@"Shell"]) iconFilename = @"shell.png"; UIImageView *leftIconView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:iconFilename]] autorelease]; customAnnotationView.leftCalloutAccessoryView = leftIconView; customAnnotationView.annotation = annotation; return customAnnotationView; } return nil; } -(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { if ([view.annotation isKindOfClass:[MyAnnotation class]]) { MyAnnotation *myAnn = (MyAnnotation *)view.annotation; NSLog(@"callout button tapped for station id %@", myAnn.stationIdKey); } else { NSLog(@"callout button tapped for annotation %@", view.annotation); } } 

(为稍微修改的问题提供一个单独的答案,原始问题是如何根据注释对象的某些属性更改注释标注图像,修改后的问题是为什么根据最新的代码,注释完全不显示,以及在viewForAnnotation中修复警告。)

在问题中最新的代码唯一明显的问题是viewDidLoad方法拼写错误,从而防止代码被调用。 请改变这个:

 - (void)viewDidload //the lowercase "l" is not correct, must be uppercase 

对此:

 - (void)viewDidLoad 

其他一些事情要检查以防万一:

  • Plist文件应该像<?xml ...><!DOCTYPE ...><plist ...><array><dict>xxx</dict><dict>yyy</dict><dict>zzz</dict></array></plist>
  • 确保像pin-green.png等图像文件已经被添加到项目中,并且完全按照这种方式命名(设备上的大写/小写字母)

接下来,要修改编译器警告在viewForAnnotation ,请将mapView参数的名称更改为其他名称,以便与视图控制器中的mapView ivar不同。 以下示例将其更改为一个aMapView (标有^^^^^^两处):

 -(MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id<MKAnnotation>)annotation ^^^^^^^^ { if ([annotation isKindOfClass:[MyAnnotation class]]) { static NSString *reuseId = @"customAnn"; MKAnnotationView *customAnnotationView = [aMapView dequeueReusableAnnotationViewWithIdentifier:reuseId]; ^^^^^^^^ if (customAnnotationView == nil) { customAnnotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId] autorelease]; UIImage *pinImage = [UIImage imageNamed:@"pin-green.png"]; [customAnnotationView setImage:pinImage]; customAnnotationView.canShowCallout = YES; UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; customAnnotationView.rightCalloutAccessoryView = rightButton; } NSString *iconFilename = @""; MyAnnotation *myAnn = (MyAnnotation *)annotation; if ([myAnn.stationIdKey isEqualToString:@"BP"]) iconFilename = @"bp-logo.png"; else if ([myAnn.stationIdKey isEqualToString:@"Caltex"]) iconFilename = @"caltex.png"; else if ([myAnn.stationIdKey isEqualToString:@"Shell"]) iconFilename = @"shell.png"; UIImageView *leftIconView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:iconFilename]] autorelease]; customAnnotationView.leftCalloutAccessoryView = leftIconView; customAnnotationView.annotation = annotation; return customAnnotationView; } return nil; } 

这是它看起来的样子(你的图钉和标注图片可能会有所不同):

绿色的针脚

壳牌标注

加德士标注

BP标注

如果你想要引脚本身有不同的图像,而不是他们的标注,那么在viewForAnnotation ,调用setImage而不是设置leftCalloutAccessoryView

另一个次要的,不相关的事情是,你不需要在for循环中调用mapView setDelegate 。 你只需要在for循环之前调用一次(如果你已经将地图视图的委托连接到了xib中的文件所有者,那么你不需要在代码中完成)。

stationIdKey属性添加到您的自定义注释类MyAnnotation并在调用addAnnotation之前创build注释时设置属性。 例如:

 //in MyAnnotation.h: @property (nonatomic, copy) NSString *stationIdKey; //and release in dealloc //in viewDidLoad before calling addAnnotation: myAnnotation.stationIdKey = [note objectForKey:@"stationIdKey"]; 

然后在viewForAnnotation ,将annotation转换为自定义类,并根据stationIdKey属性设置图标:

 NSString *iconFilename = @""; MyAnnotation *myAnn = (MyAnnotation *)annotation; if ([myAnn.stationIdKey isEqualToString:@"BP"]) iconFilename = @"bp-logo.png"; else if ([myAnn.stationIdKey isEqualToString:@"Caltex"]) iconFilename = @"caltex.png"; else if ([myAnn.stationIdKey isEqualToString:@"Shell"]) iconFilename = @"shell.png"; UIImageView *leftIconView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:iconFilename]] autorelease]; 

(还有一些其他的问题,我将在后面添加详细信息。)


编辑:
对不起,我不清楚上面显示的viewForAnnotation代码只能代替设置leftCalloutAccessoryView的现有代码的leftCalloutAccessoryView 。 这不是整个代表方法。

警告Control reaches end of non-void function意味着即使该方法声明为返回MKAnnotationView * ,replace代码也不会返回值。

以下是其他无关build议更改的完整方法:

 -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { if ([annotation isKindOfClass:[MyAnnotation class]]) { static NSString *reuseId = @"customAnn"; MKAnnotationView *customAnnotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId]; if (customAnnotationView == nil) { customAnnotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId] autorelease]; UIImage *pinImage = [UIImage imageNamed:@"pin-green.png"]; [customAnnotationView setImage:pinImage]; customAnnotationView.canShowCallout = YES; UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; customAnnotationView.rightCalloutAccessoryView = rightButton; } NSString *iconFilename = @""; MyAnnotation *myAnn = (MyAnnotation *)annotation; if ([myAnn.stationIdKey isEqualToString:@"BP"]) iconFilename = @"bp-logo.png"; else if ([myAnn.stationIdKey isEqualToString:@"Caltex"]) iconFilename = @"caltex.png"; else if ([myAnn.stationIdKey isEqualToString:@"Shell"]) iconFilename = @"shell.png"; UIImageView *leftIconView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:iconFilename]] autorelease]; customAnnotationView.leftCalloutAccessoryView = leftIconView; customAnnotationView.annotation = annotation; return customAnnotationView; } return nil; } 

我已经添加了以下内容:

  • 如果注释types是MyAnnotation创build一个自定义注释视图,否则返回nil 。 所以,如果您稍后决定显示其他types的注释,如用户位置,它仍然会工作。
  • 通过调用dequeue方法实现注释视图重用。 如果您有很多注释,这可以提高性能。
  • 只有当视图是新创build的(而不是被重新使用)时,才将注释视图属性的设置移动到每个注释不更改的位置。
  • 删除了rightButton addTarget:action: call。 我强烈build议你实现地图视图的calloutAccessoryControlTapped委托方法,而不是自定义的方法。 因此,而不是一个annotationViewClick:方法,实现委托方法,如下所示:

     -(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { if ([view.annotation isKindOfClass:[MyAnnotation class]]) { MyAnnotation *myAnn = (MyAnnotation *)view.annotation; NSLog(@"callout button tapped for station id %@", myAnn.stationIdKey); } else { NSLog(@"callout button tapped for annotation %@", view.annotation); } } 

最后,在viewDidLoad ,你正在使用alloc创buildanns数组,但是你并没有调用release来导致内存泄漏。

用这个自动发布版本(build议)replaceanns数组的alloc + init:

 NSArray *anns = [NSArray arrayWithContentsOfFile:path]; 

或者在viewDidLoad方法结束之前的for循环之后添加它:

 [anns release];