#iphone #mkmapview #mkannotationview
#iPhone #mkmapview #mkannotationview
Вопрос:
У меня есть приложение для iPhone, которое показывает местоположения пользователей на карте, и цель состоит в том, чтобы размер маркера был пропорционален популярности местоположения. Более популярные места получают аннотации немного большего размера.
У меня есть пользовательские MKAnnotation и MKAnnotationView для отображения маркеров. Я пытался использовать пользовательский MKAnnotationView для отображения маркеров разного размера, но всегда отображаются изображения одинакового размера.
Вот класс.
Любые советы или предложения приветствуются:
#import "MapAnnotationView.h"
@implementation MapAnnotationView
- (id)initWithAnnotation:(id)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
MapAnnotation * myAnnotation = (MapAnnotation *) annotation;
self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];
// Figure out if in 'normal' mode or 'compare' mode
// normal
if (myAnnotation.visited != nil) {
if ([myAnnotation.visited boolValue] == YES) {
self.image = [UIImage imageNamed:@"visited.png"];
} else if ([myAnnotation.visited boolValue] == NO) {
self.image = [UIImage imageNamed:@"unvisited.png"];
}
// compare
} else {
// On both maps
if ([myAnnotation.onLoggedInUsersMap boolValue] == YES amp;amp; [myAnnotation.onComparisonMap boolValue] == YES) {
if ([myAnnotation.mapCount intValue] == 1) {
self.image = [UIImage imageNamed:@"both_small.png"];
} if ([myAnnotation.mapCount intValue] < 5) {
self.image = [UIImage imageNamed:@"both_medium.png"];
} else {
self.image = [UIImage imageNamed:@"both_large.png"];
}
// Only on comparison's map
} else if ([myAnnotation.onLoggedInUsersMap boolValue] == NO amp;amp; [myAnnotation.onComparisonMap boolValue] == YES) {
if ([myAnnotation.mapCount intValue] == 1) {
self.image = [UIImage imageNamed:@"compare_small.png"];
} if ([myAnnotation.mapCount intValue] < 5) {
self.image = [UIImage imageNamed:@"compare_medium.png"];
} else {
self.image = [UIImage imageNamed:@"compare_large.png"];
}
// Only on owner's map
} else {
if ([myAnnotation.mapCount intValue] == 1) {
self.image = [UIImage imageNamed:@"owner_small.png"];
} if ([myAnnotation.mapCount intValue] < 5) {
self.image = [UIImage imageNamed:@"owner_medium.png"];
} else {
self.image = [UIImage imageNamed:@"owner_large.png"];
}
}
}
return self;
}
@end
И вот метод viewForAnnotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation {
if ([annotation class] == MKUserLocation.class) {
return nil;
}
MapAnnotationView *aView = [[MapAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"location"];
[aView setEnabled:YES];
[aView setCanShowCallout:YES];
aView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return aView;
}
Комментарии:
1. Вы проверили, достигает ли выполнение логики MapCount в методе init? Показывает ли он правильное количество карт? Покажите метод viewForAnnotation. Как устанавливается MapCount и обновляется ли он когда-либо после добавления аннотации к карте?
2. Да: логика MapCount работает (NSLog, размещенный в каждом операторе if, выводит правильные итоговые данные и корректно обновляется по мере панорамирования карты). MapCount является свойством каждого объекта MKAnnotation; оно устанавливается вызовом сервера и не изменяется.
Ответ №1:
Проблема в том, что в большом условном обозначении в методе инициализации отсутствуют три else
:
// On both maps
if ([myAnnotation.onLoggedInUsersMap boolValue] == YES amp;amp; [myAnnotation.onComparisonMap boolValue] == YES) {
if ([myAnnotation.mapCount intValue] == 1) {
self.image = [UIImage imageNamed:@"both_small.png"];
} else if ([myAnnotation.mapCount intValue] < 5) { // <----------------
// ^-- was missing else before the if
self.image = [UIImage imageNamed:@"both_medium.png"];
} else {
self.image = [UIImage imageNamed:@"both_large.png"];
}
// Only on comparison's map
} else if ([myAnnotation.onLoggedInUsersMap boolValue] == NO amp;amp; [myAnnotation.onComparisonMap boolValue] == YES) {
if ([myAnnotation.mapCount intValue] == 1) {
self.image = [UIImage imageNamed:@"compare_small.png"];
} else if ([myAnnotation.mapCount intValue] < 5) { // <----------------
// ^-- was missing else before the if
self.image = [UIImage imageNamed:@"compare_medium.png"];
} else {
self.image = [UIImage imageNamed:@"compare_large.png"];
}
// Only on owner's map
} else {
if ([myAnnotation.mapCount intValue] == 1) {
self.image = [UIImage imageNamed:@"owner_small.png"];
} else if ([myAnnotation.mapCount intValue] < 5) { // <----------------
// ^-- was missing else before the if
self.image = [UIImage imageNamed:@"owner_medium.png"];
} else {
self.image = [UIImage imageNamed:@"owner_large.png"];
}
Две отдельные, не связанные проблемы:
- утечка памяти
viewForAnnotation
из-за того, что она не освобождаетсяaView
- следует использовать
dequeueReusableAnnotationViewWithIdentifier
вviewForAnnotation
Итак, viewForAnnotation
метод должен выглядеть следующим образом:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation {
if ([annotation class] == MKUserLocation.class) {
return nil;
}
MapAnnotationView *aView = (MapAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"location"];
if (!aView)
{
aView = [[[MapAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:@"location"] autorelease];
[aView setEnabled:YES];
[aView setCanShowCallout:YES];
aView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
aView.annotation = annotation;
}
return aView;
}
Комментарии:
1. Большое спасибо; это сработало. Мне пришлось внести небольшое изменение в логику if / else предлагаемого вами метода viewForAnnotation: мой MapController позволяет пользователю переключать различные состояния карты (код не показан). Я добавил метод обновления к MapAnnotationView, который я вызываю после строки AView.annotation = annotation, и он вызывает всю логику представления в MKAnnotationView, чтобы убедиться, что отображается правильное изображение.