Настроить просмотр выноски MKAnnotation?
У меня есть MKPointAnnotation
:
let ann = MKPointAnnotation()
self.ann.coordinate = annLoc
self.ann.title = "Customize me"
self.ann.subtitle = "???"
self.mapView.addAnnotation(ann)
Это выглядит так:
Как я могу настроить это представление выноски, чтобы создать мое собственное представление вместо предопределенного?
3 ответа
Прежде всего следует отметить, что простейшие изменения в выноске возможны путем простой настройки свойств предоставляемой системой выноски, но путем настройки правого и левого аксессуаров (через rightCalloutAccessoryView
а также leftCalloutAccessoryView
). Вы можете сделать эту конфигурацию в viewForAnnotation
,
В iOS 9 у нас теперь есть доступ к detailCalloutAccessoryView
который заменяет субтитры выноски потенциально визуально насыщенным представлением, в то же время наслаждаясь автоматическим воспроизведением всплывающей подсказки (использование автоматической разметки делает это проще).
Например, здесь выноска, которая использовала MKSnapshotter
предоставить изображение для просмотра изображения в дополнительном элементе выноски, как показано в видео WWDC 2015 Что нового в MapKit:
Вы можете достичь этого с помощью чего-то вроде:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let identifier = "MyCustomAnnotation"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
} else {
annotationView!.annotation = annotation
}
configureDetailView(annotationView!)
return annotationView
}
func configureDetailView(annotationView: MKAnnotationView) {
let width = 300
let height = 200
let snapshotView = UIView()
let views = ["snapshotView": snapshotView]
snapshotView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[snapshotView(300)]", options: [], metrics: nil, views: views))
snapshotView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[snapshotView(200)]", options: [], metrics: nil, views: views))
let options = MKMapSnapshotOptions()
options.size = CGSize(width: width, height: height)
options.mapType = .SatelliteFlyover
options.camera = MKMapCamera(lookingAtCenterCoordinate: annotationView.annotation!.coordinate, fromDistance: 250, pitch: 65, heading: 0)
let snapshotter = MKMapSnapshotter(options: options)
snapshotter.startWithCompletionHandler { snapshot, error in
if snapshot != nil {
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
imageView.image = snapshot!.image
snapshotView.addSubview(imageView)
}
}
annotationView.detailCalloutAccessoryView = snapshotView
}
Если вы ищете более радикальную переработку выноски или вам нужна поддержка версий iOS до 9, это займет больше времени. Процесс влечет за собой (а) отключение выноски по умолчанию; и (б) добавление вашего собственного вида, когда пользователь нажимает на существующий вид аннотации (то есть визуальный значок на карте).
Сложность тогда возникает в дизайне выноски, где вы должны нарисовать все, что вы хотите, видимым. Например, если вы хотите нарисовать пузырь, чтобы всплыть ощущение вызова, вы должны сделать это самостоятельно. Но, имея некоторое представление о том, как рисовать фигуры, изображения, текст и т. Д., Вы сможете отобразить выноску, которая достигает желаемого UX:
Просто добавьте представление как подпредставление самого представления аннотации и соответствующим образом скорректируйте его ограничения:
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
let calloutView = ...
calloutView.translatesAutoresizingMaskIntoConstraints = false
calloutView.backgroundColor = UIColor.lightGrayColor()
view.addSubview(calloutView)
NSLayoutConstraint.activateConstraints([
calloutView.bottomAnchor.constraintEqualToAnchor(view.topAnchor, constant: 0),
calloutView.widthAnchor.constraintEqualToConstant(60),
calloutView.heightAnchor.constraintEqualToConstant(30),
calloutView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor, constant: view.calloutOffset.x)
])
}
См. https://github.com/robertmryan/CustomMapViewAnnotationCalloutSwift для примера создания собственного представления выноски. Это добавляет только две метки, но это иллюстрирует тот факт, что вы можете нарисовать пузырь любой фигуры, которую вы хотите, использовать ограничения для определения размера выноски и т. Д.
Нет необходимости создавать пользовательский класс MKAnnotationView, просто создайте пустое представление.xib и спроектируйте.xib как ваше требование. Напишите свой бизнес логин в классе UIView Swift.
Добавить вид на
func mapView(_ mapView: MKMapView, viewFor аннотация: MKAnnotation) -> MKAnnotationView? {
...
}
такой метод, как annotationView?.detailCalloutAccessoryView = customView
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) {
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
} else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
}
if let annotation = annotation as? HPAnnotation {
annotationView?.canShowCallout = true
let customView = Bundle.main.loadNibNamed("HPAnnotationView", owner: self, options: nil)?.first as! HPAnnotationView
customView.labelName.text = annotation.annotationTitle
annotationView?.detailCalloutAccessoryView = customView
}
return annotationView
}
Если вы хотите, чтобы динамическое значение отображалось в представлении выноски, сначала создайте пользовательский класс MKAnnotation, где вы можете передавать объекты по мере необходимости.
import MapKit
import AddressBook
import UIKit
class HPAnnotation: NSObject, MKAnnotation {
let title: String?
let annotationTitle: String
init(title: String, annotationTitle: String = "") {
self.title = title
self.annotationTitle = annotationTitle
}
var subtitle: String? {
return details
}
}
и передать значение при создании аннотации
for index in 0..<searchPeopleArray.count {
let annotation = HPAnnotation(title: "", annotationTitle: "")
mapView.addAnnotation(annotation)
}
NB. Здесь HPAnnotationView - это мой пользовательский класс представления и имя XIB. HPAnnotation - это мой пользовательский MKAnnotation.
Создать файл какао с классическим типом MKAnnotationView
Файл CustomeAnnotationView.h
@interface CustomeAnnotationView : MKAnnotationView
@property (strong, nonatomic) UIButton *buttonCustomeCallOut;
- (void)setSelected:(BOOL)selected animated:(BOOL)animated;
@end
Файл CustomeAnnotationView.m
@implementation CustomeAnnotationView
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated{
[super setSelected:selected animated:animated];
if(selected)
{
self.buttonCustomeCallOut = [UIButton buttonWithType:UIButtonTypeCustom];//iconShare//iconShareBlue
[self.buttonCustomeCallOut addTarget:self action:@selector(buttonHandlerCallOut:) forControlEvents:UIControlEventTouchDown];
[self.buttonCustomeCallOut setBackgroundColor:[UIColor blueColor]];
[self.buttonCustomeCallOut setFrame:CGRectMake(-40,-80, 100, 100)];
[self addSubview:self.buttonCustomeCallOut];
[self.buttonCustomeCallOut setUserInteractionEnabled:YES];
}
else
{
//Remove your custom view...
[self.buttonCustomeCallOut setUserInteractionEnabled:NO];
[self.buttonCustomeCallOut removeFromSuperview];
self.buttonCustomeCallOut=nil;
}
}
-(void)buttonHandlerCallOut:(UIButton*)sender{
NSLog(@"Annotation Clicked");
}
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
UIView* v = [super hitTest:point withEvent:event];
if (v != nil)
{
[self.superview bringSubviewToFront:self];
}
return v;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
CGRect rec = self.bounds;
BOOL isIn = CGRectContainsPoint(rec, point);
if(!isIn)
{
for (UIView *v in self.subviews)
{
isIn = CGRectContainsPoint(v.frame, point);
if(isIn)
break;
}
}
return isIn;
}
@end
поместите этот код там, где вы хотите создать обычай вызывать
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = @"CustAnnotation";
CustomeAnnotationView *annotationView = (CustomeAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[CustomeAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
}
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
annotationView.centerOffset = CGPointMake(0,-10);//-18
return annotationView;
}