Personalizar la vista de llamada de MKAnnotation?

Tengo una MKPointAnnotation :

 let ann = MKPointAnnotation() self.ann.coordinate = annLoc self.ann.title = "Customize me" self.ann.subtitle = "???" self.mapView.addAnnotation(ann) 

Se parece a esto:

enter image description here

¿Cómo puedo personalizar esta vista de llamada para crear mi propia vista en lugar de la vista predefinida?

En primer lugar, debe tenerse en cuenta que los cambios más simples en la llamada se activan simplemente ajustando las propiedades de la llamada proporcionada por el sistema, pero personalizando los accesorios derecho e izquierdo (a través de rightCalloutAccessoryView y leftCalloutAccessoryView ). Puede hacer esa configuración en viewForAnnotation .

En iOS 9, ahora tenemos acceso a detailCalloutAccessoryView que reemplaza el subtítulo de la leyenda con una vista potencialmente rica visualmente, mientras disfruta de la reproducción automática de la burbuja de llamada (el uso del diseño automático lo hace más fácil).

Por ejemplo, aquí hay un rótulo que utilizó un MKSnapshotter para suministrar la imagen para una vista de imagen en el accesorio de rótulo detallado, como se demostró en el video de WWDC 2015 Novedades en MapKit :

enter image description here

Puedes lograr esto con algo como:

 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 } 

Si está buscando un rediseño más radical de la leyenda o necesita soportar versiones de iOS anteriores a la 9, se necesita más trabajo. El proceso implica (a) desactivar el texto predeterminado; y (b) agregar su propia vista cuando el usuario toca en la vista de anotación existente (es decir, el pin visual en el mapa).

La complejidad luego viene en el diseño de la leyenda, donde tiene que dibujar todo lo que desea visible. Por ejemplo, si desea dibujar una burbuja para ceder la sensación de popover de la llamada, debe hacerlo usted mismo. Sin embargo, con cierta familiaridad con la forma de dibujar formas, imágenes, texto, etc., debería poder representar una leyenda que logre el UX deseado:

texto personalizado

Simplemente agregue la vista como una subvista de la vista de anotación y ajuste sus restricciones en consecuencia:

 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) ]) } 

Consulte https://github.com/robertmryan/CustomMapViewAnnotationCalloutSwift para ver un ejemplo de cómo crear su propia vista de texto destacado. Esto solo agrega dos tags, pero ilustra el hecho de que puede dibujar la burbuja de cualquier forma que desee, usar restricciones para dictar el tamaño de la leyenda, etc.

Crear un archivo Cocoa con classtype MKAnnotationView

Archivo CustomeAnnotationView.h

 @interface CustomeAnnotationView : MKAnnotationView @property (strong, nonatomic) UIButton *buttonCustomeCallOut; - (void)setSelected:(BOOL)selected animated:(BOOL)animated; @end 

Archivo 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 

coloque este código donde desee crear una llamada de atención

 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )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; } 

No es necesario crear la clase MKAnnotationView Custom para crear una vista vacía .xib y diseñar .xib como requisito. Escriba su inicio de sesión comercial en la clase rápida UIView.

Agregar la vista en

func mapView (_ mapView: MKMapView, viewPara la anotación: MKAnnotation) -> MKAnnotationView? {

}

método como anotaciónView? .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 } 

Si desea que se muestre el valor dynamic en la vista de llamadas, primero realice la clase personalizada MKAnnotation, donde puede pasar los objetos que necesite.

 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 } 

}

y pasa el valor al crear la anotación

  for index in 0.. 

NB: Aquí HPAnnotationView es mi clase de vista personalizada y el nombre xib. HPAnnotation es mi MKAnnotation personalizada.