如何显示通过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; }
这是它看起来的样子(你的图钉和标注图片可能会有所不同):
如果你想要引脚本身有不同的图像,而不是他们的标注,那么在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];