Cómo agregar una vista personalizada en las llamadas de anotación del mapa

Aquí está mi código. Deseo agregar mi propia vista de llamada personalizada en lugar de la predeterminada de iOS. Sé que solo hay una leyenda a la izquierda y una vista de leyenda derecha, pero necesito agregar una vista tipo de información sobre herramientas con mi propio fondo y etiqueta.

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation { MKAnnotationView *userAnnotationView = nil; if ([annotation isKindOfClass:MKUserLocation.class]) { userAnnotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"UserLocation"]; if (userAnnotationView == nil) { userAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"UserLocation"]; } else userAnnotationView.annotation = annotation; userAnnotationView.enabled = YES; userAnnotationView.canShowCallout = YES; userAnnotationView.image = [UIImage imageNamed:@"map_pin.png"]; UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0,0,141,108)]; view.backgroundColor = [UIColor clearColor]; UIImageView *imgView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"toltip.png"]]; [view addSubview:imgView]; userAnnotationView.leftCalloutAccessoryView = view; return userAnnotationView; } } 

Imagen de referencia

Tuve el mismo problema y terminé haciendo lo siguiente:

Cuando recibo callback mapView

 -(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view 

(es hora de que quiera mostrar mi CalloutView personalizado)

Utilizo la vista recibida como parámetro * ( vista de MKAnnotationView ) (que es una vista de pin) y simplemente agrego mi vista personalizada a esa vista de pin usando

  [view addSubview:customView]; 

Agregará su vista personalizada en la parte superior de esa vista de pin, por lo que si queremos que esté encima del pin, tenemos que cambiar la propiedad del centro de visualización personalizado de esta manera:

 CGRect customViewRect = customView.frame; CGRect rect = CGRectMake(-customViewRect.size.width/2, -customViewRect.size.height-7, customViewRect.size.width, customViewRect.size.height); customView.frame = rect; [view addSubview:customView]; 

En mi caso, parece que esto

enter image description here

! NOTA :

Hay una advertencia que, sin embargo, se puede arreglar fácilmente, su vista personalizada ignorará los eventos táctiles , debido a que mapView trabaja con toques de manera diferente. Aquí hay una solución rápida :

1) La subclase MKAnnotationView (o MKPinAnnotationView depende de lo que necesite)

2) en tu delegado mapView

 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation 

use su subclase en lugar de MKAnnotationView / MKPinAnnotationView

3) en su subclase .m, el archivo anula dos métodos de la siguiente manera:

 - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { UIView* hitView = [super hitTest:point withEvent:event]; if (hitView != nil) { [self.superview bringSubviewToFront:self]; } return hitView; } - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event { CGRect rect = self.bounds; BOOL isInside = CGRectContainsPoint(rect, point); if(!isInside) { for (UIView *view in self.subviews) { isInside = CGRectContainsPoint(view.frame, point); if(isInside) break; } } return isInside; } 

¡Todo listo!

Creé una biblioteca para mostrar textos personalizados.

DXCustomCallout-ObjC

¡Puede pasar cualquier vista personalizada para el texto destacado! También es compatible con eventos para UIControls.

Llamada personalizada

A la mejor respuesta anterior en Swift

Esto puede ahorrar algunos minutos para reescribirse.

!NOTA:

Hay una advertencia que, sin embargo, se puede arreglar fácilmente, su vista personalizada ignorará los eventos táctiles, debido a que mapView trabaja con toques de manera diferente. Aquí hay una solución rápida:

1) La subclase MKAnnotationView (o MKPinAnnotationView depende de lo que necesite)

2) en tu delegado mapView

 func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? 

use su subclase en lugar de MKAnnotationView / MKPinAnnotationView

3) en su subclase .m, el archivo anula dos métodos de la siguiente manera:

 override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { let hitView = super.hitTest(point, withEvent: event) if (hitView != nil) { self.superview?.bringSubviewToFront(self) } return hitView; } override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { let rect = self.bounds var isInside = CGRectContainsPoint(rect, point) if(!isInside) { for view in self.subviews { isInside = CGRectContainsPoint(view.frame, point) break; } } return isInside } 

Acabo de crear una leyenda personalizada para mi vista de mapa que evita problemas con la eliminación de la leyenda cuando se toca. Aquí hay una Gráfica con los pasos que tomé.

Puedes usar esta biblioteca. También proporciona una plantilla lista para usar para la vista de llamadas. Agrega animaciones geniales y una vista de anclaje para tus vistas personalizadas.

https://github.com/okhanokbay/MapViewPlus

enter image description here enter image description here