Ответ 1
Существует несколько подходов к настройке выносок:
-
Самый простой способ - использовать существующие аксессуары для правого и левого выноса и поместить вашу кнопку в одну из них. Например:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { static NSString *identifier = @"MyAnnotationView"; if ([annotation isKindOfClass:[MKUserLocation class]]) { return nil; } MKPinAnnotationView *view = (id)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier]; if (view) { view.annotation = annotation; } else { view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]; view.canShowCallout = true; view.animatesDrop = true; view.rightCalloutAccessoryView = [self yesButton]; } return view; } - (UIButton *)yesButton { UIImage *image = [self yesButtonImage]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(0, 0, image.size.width, image.size.height); // don't use auto layout [button setImage:image forState:UIControlStateNormal]; [button addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventPrimaryActionTriggered]; return button; } - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { NSLog(@"%s", __PRETTY_FUNCTION__); }
Это дает:
-
Если вам действительно не нравится кнопка справа, где обычно идут аксессуары, вы можете отключить этот аксессуар, а iOS 9 дает возможность указать
detailCalloutAccessoryView
, который заменяет субтитры выносок на любой вид, который вы хотите:- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { static NSString *identifier = @"MyAnnotationView"; if ([annotation isKindOfClass:[MKUserLocation class]]) { return nil; } MKPinAnnotationView *view = (id)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier]; if (view) { view.annotation = annotation; } else { view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]; view.canShowCallout = true; view.animatesDrop = true; } view.detailCalloutAccessoryView = [self detailViewForAnnotation:annotation]; return view; } - (UIView *)detailViewForAnnotation:(PlacemarkAnnotation *)annotation { UIView *view = [[UIView alloc] init]; view.translatesAutoresizingMaskIntoConstraints = false; UILabel *label = [[UILabel alloc] init]; label.text = annotation.placemark.name; label.font = [UIFont systemFontOfSize:20]; label.translatesAutoresizingMaskIntoConstraints = false; label.numberOfLines = 0; [view addSubview:label]; UIButton *button = [self yesButton]; [view addSubview:button]; NSDictionary *views = NSDictionaryOfVariableBindings(label, button); [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:views]]; [view addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]]; [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]-[button]|" options:0 metrics:nil views:views]]; return view; } - (UIButton *)yesButton { UIImage *image = [self yesButtonImage]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.translatesAutoresizingMaskIntoConstraints = false; // use auto layout in this case [button setImage:image forState:UIControlStateNormal]; [button addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventPrimaryActionTriggered]; return button; }
Это дает:
-
Если вы действительно хотите самостоятельно разработать настраиваемую выноску, Руководство по программированию местоположения и карт описывает шаги:
В приложении iOS рекомендуется использовать метод делегата
mapView:annotationView:calloutAccessoryControlTapped:
для ответа, когда пользователи нажимают на элемент управления представлениями (пока элемент управления является потомкомUIControl
). В вашей реализации этого метода вы можете узнать личность представления аннотаций видов выносок, чтобы вы знали, какую аннотацию пользователь прослушивал. В приложении Mac приложение просмотра представлений точек вызова может реализовать метод действия, который отвечает, когда пользователь нажимает элемент управления в виде выноска.При использовании пользовательского представления вместо стандартной выноски вам необходимо выполнить дополнительную работу, чтобы убедиться, что выноска отображается и скрывается соответствующим образом, когда пользователи взаимодействуют с ней. В приведенных ниже шагах описывается процесс создания настраиваемой выноски, содержащей кнопку:
-
Создайте подкласс
NSView
илиUIView
, который представляет собой настраиваемую выноску. Вероятно, что подкласс должен реализовать методdrawRect:
для рисования вашего пользовательского контента. -
Создайте контроллер представления, который инициализирует представление выноска и выполняет действие, связанное с кнопкой.
-
В представлении аннотации выполните
hitTest:
для ответа на хиты, которые находятся за пределами границ аннотаций, но внутри границ разрешений выносок, как показано в листинге 6-7. -
В представлении аннотации внедряйте
setSelected:animated:
, чтобы добавить ваше представление выноски в качестве подвидности аннотационного представления, когда пользователь щелкает или забирает его. -
Если вид выноска уже отображается, когда пользователь его выбирает, метод
setSelected:
должен удалить подзону callout из представления аннотации (см. листинг 6-8). -
В представлении аннотаций
initWithAnnotation:
установите для свойстваcanShowCallout
значениеNO
, чтобы карта не отображала стандартную выноску, когда пользователь выбирает аннотацию.
Пока он в Swift, https://github.com/robertmryan/CustomMapViewAnnotationCalloutSwift иллюстрирует пример того, как вы можете выполнить эту полную настройку выноски (например, изменить форму выноски пузырь, изменение цвета фона и т.д.).
-
-
В предыдущем пункте описываются довольно сложные сценарии (т.е. вам нужно написать свой собственный код для обнаружения ответвлений за пределами представления, чтобы отменить его). Если вы поддерживаете iOS 9, вы можете просто использовать контроллер просмотра popover, например:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { static NSString *identifier = @"MyAnnotationView"; if ([annotation isKindOfClass:[MKUserLocation class]]) { return nil; } MKPinAnnotationView *view = (id)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier]; if (view) { view.annotation = annotation; } else { view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]; view.canShowCallout = false; // note, we're not going to use the system callout view.animatesDrop = true; } return view; } - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view { PopoverController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"AnnotationPopover"]; controller.modalPresentationStyle = UIModalPresentationPopover; controller.popoverPresentationController.sourceView = view; // adjust sourceRect so it centered over the annotation CGRect sourceRect = CGRectZero; sourceRect.origin.x += [mapView convertCoordinate:view.annotation.coordinate toPointToView:mapView].x - view.frame.origin.x; sourceRect.size.height = view.frame.size.height; controller.popoverPresentationController.sourceRect = sourceRect; controller.annotation = view.annotation; [self presentViewController:controller animated:TRUE completion:nil]; [mapView deselectAnnotation:view.annotation animated:true]; // deselect the annotation so that when we dismiss the popover, the annotation won't still be selected }