2009-06-11 16 views
73

Estoy trabajando en un MKMapView con el pin de color habitual como puntos de ubicación. Me gustaría poder mostrar la leyenda sin tocar el pin.Cómo desencadenar la vista de llamada de MKAnnotationView sin tocar el pin?

¿Cómo debo hacer eso? Llamar al setSelected:YES en la vista de anotación no hizo nada. Estoy pensando en simular un toque en el pin, pero no estoy seguro de cómo hacerlo.

+0

Mi solución en otra pregunta: http://stackoverflow.com/a/13026353/736384 –

Respuesta

35

Bien, aquí está la solución a este problema.

Para mostrar la leyenda, utilice el método MKMapViewselectAnnotation:animated.

+3

Esto no ayuda. Puedo llamar esto y no siempre animará la selección. La primera vez, sí. Cada vez después de eso, no, incluso si se llama al método. La solución de benvolioT tampoco funciona para mí. Incluso si llamo selectAnnotation: animated: directamente, cuando se conoce la anotación, no funciona. Los mismos problemas que antes. :( –

+0

@Joe Creo que debe eliminar la anotación antes de recuperar para que se muestre la animación. –

+0

comentando que si pin está en * estado * seleccionado, y lo selecciona nuevamente, permanece en el mismo estado * seleccionado * hasta lo deseleccionas o el usuario lo deselecciona. – dklt

9

Esto no funciona para mí. Sospecho que hay un error en la API de MapKit.

Ver este enlace para los detalles de otra persona para que esto no está funcionando: http://www.iphonedevsdk.com/forum/iphone-sdk-development/19740-trigger-mkannotationview-callout-bubble.html#post110447

--edit--

bien después de atornillar con esto durante un tiempo, aquí es lo que he sido capaz de hacer el trabajo:

for (id<MKAnnotation> currentAnnotation in mapView.annotations) {  
    if ([currentAnnotation isEqual:annotationToSelect]) { 
     [mapView selectAnnotation:currentAnnotation animated:FALSE]; 
    } 
} 

Nota, esto requiere la implementación de - (BOOL)isEqual:(id)anObject para su clase que implementa el protocolo MKAnnotation.

+0

basado en esto obtuve [mapView selectAnnotation: [mapView.annotations objectAtIndex: 0] animated: false]; para trabajar para elegir la primera anotación. – Andiih

+0

Esto funciona y es extremadamente irritante . –

6

Si solo desea abrir la llamada para la última anotación que ha agregado, intente esto, funciona para mí.

[mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES];

+0

esto funciona muy bien – confile

61

Pero hay una trampa para obtener una solución de benvolioT funcione, el código

for (id<MKAnnotation> currentAnnotation in mapView.annotations) {  
    if ([currentAnnotation isEqual:annotationToSelect]) { 
     [mapView selectAnnotation:currentAnnotation animated:FALSE]; 
    } 
} 

deberían ser llamados desde - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView, y en ninguna otra parte.

La secuencia en la que los diversos métodos como viewWillAppear, viewDidAppear de UIViewController y la - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView se llama es diferente entre la primera vez que el mapa se carga con una localización particular y los tiempos posteriores, el mapa se muestra con la misma ubicación. Esto es un poco complicado.

+3

Nada complicado Sólo necesita saber para llamar:!..!! [MAPview selectAnnotation] en lugar de [anotación setSelected] Gracias – bentford

+0

Muchas gracias – fuzz

+0

bien esto funcionó la primera vez de forma automática Pero ahora es. ¿ya no funciona? ¿qué? - (vacío) mapViewDidFinish LoadingMap: (MKMapView *) _ mapView { \t [mapView selectAnnotation: addAnnotation animated: YES]; } – fuzz

3

Debido a algo así como el código mostrado por benvolioT, que sospecho que existe en el sistema, cuando utilicé selectAnnotation: animation: method, no mostró el callOut, supuse que el motivo era porque ya estaba seleccionado y se evitó pedirle a MapView que volviera a dibujar callOut en el mapa utilizando el título y el subtítulo de la anotación.

Entonces, la solución fue simplemente deseleccionarlo primero y volver a seleccionarlo.

E.g: Primero, necesitaba hacer esto en el método touchMoved de Apple (es decir, cómo arrastrar un AnnotationView) para ocultar el callOut. (Simplemente usando annotation.canShowAnnotation = NO solo no funciona, ya que sospecho que necesita volver a dibujar. La anulación de la selección provoca la acción necesaria. Además, deseleccionar solo no hizo ese truco, el callOut desapareció solo una vez y se volvió a dibujar inmediatamente. fue la sugerencia de que se volvió a seleccionar automáticamente).

annotationView.canShowAnnotation = NO; 
[mapView deselectAnnotation:annotation animated:YES]; 

Luego, basta con el siguiente código en el método touchEnded no traer de vuelta la llamada (La anotación se ha seleccionado automáticamente por el sistema en ese momento, y, presumiblemente, el nuevo trazado de la llamada nunca se occrrs):

annotationView.canShowAnnotation = YES; 
[mapView selectAnnotation:annotation animated:YES]; 

la solución fue:

annotationView.canShowAnnotation = YES; 
[mapView deselectAnnotation:annotation animated:YES]; 
[mapView selectAnnotation:annotation animated:YES]; 

Esto simplemente volvió a comprar la llamada, es de suponer que re-inició el proceso de volver a dibujar la llamada por el MAPview.

Estrictamente hablando, debería detectar si la anotación es la anotación actual o no (seleccionada, lo que sé que es) y si la callOut se está mostrando o no (que no sé) y decide volver a dibujarla en consecuencia, eso sería mejor. Sin embargo, aún no he encontrado el método de detección de callOut y tratar de hacerlo es algo innecesario en este momento.

1

La respuesta de Steve Shi me dejó claro que selectAnnotation debe llamarse desde el método mapViewDidFinishLoadingMap. Desafortunadamente no puedo votar pero quiero agradecerles aquí.

5

leí la API cuidadosamente y finalmente he encontrado el problema:


Si la anotación especificado no está en pantalla, y por lo tanto no tiene una vista de anotación asociada, este método no tiene ningún efecto.

Así que puede esperar un tiempo (por ejemplo, 3 segundos) y luego realizar esta acción. Entonces funciona

+1

Eso está creando una condición de carrera. ¿No hay un evento que indique que el mapa ha terminado de mostrarse y que puede usar para activar la pantalla? –

32

Suponiendo que desea que la última vista de anotación para ser seleccionados, se puede poner el código de abajo:

[mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES]; 

en el delegado a continuación:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views 
{ 
    //Here 
    [mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES]; 
} 
+0

¡Esta sería la solución que funcionó para mí! muchas gracias! –

+0

¡Cuidado! Este método delegado se llama para las anotaciones que están actualmente visibles, es decir, aquellas que están dentro de la región del mapa que se muestra actualmente en la pantalla. –

21

Ok, añadir con éxito el texto destacado que es necesario llamar a selectAnnotation: animado después de que se hayan agregado todas las vistas de anotación, utilizando el delegado didAddAnnotationViews:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views{ 
    for (id<MKAnnotation> currentAnnotation in mapView.annotations) {  
     if ([currentAnnotation isEqual: annotationToSelect]) { 
      [mapView selectAnnotation:currentAnnotation animated:YES]; 
     } 
    } 
} 
+0

Descubrí que esta es la mejor manera de hacerlo, ya que este método se activará al agregar la anotación. –

+1

Este método elimina la llamada junto con el pin, ¿hay alguna solución que pueda mostrar la leyenda justo después de que se haya soltado el pin en el mapa? – Michael

12

Después de probar una variedad de respuestas a este hilo, finalmente se me ocurrió esto. Su funcionamiento es muy fiable, que todavía no han visto fracasar:

- (void)mapView:(MKMapView *)aMapView didAddAnnotationViews:(NSArray *)views; 
{ 
    for(id<MKAnnotation> currentAnnotation in aMapView.annotations) 
    {  
     if([currentAnnotation isEqual:annotationToSelect]) 
     { 
      NSLog(@"Yay!"); 
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_current_queue(),^
      { 
       [aMapView selectAnnotation:currentAnnotation animated:YES]; 
      }); 
     } 
    } 
} 

El bloque se utiliza para retrasar ligeramente, ya que sin ella la llamada no se puede mostrar correctamente.

+2

Increíble. Es un problema y está en una condición de carrera, pero funciona. Lo que sucede aquí es que con el guión gráfico haciendo casi todo, no es obvio que el delegado necesita estar conectado a través del guión gráfico, si no ha tocado MKMapViews en 3 meses. Esto es algo que el guión gráfico debería hacer automáticamente, o al menos advertirle. Prefiero definir el mapKit ref en el init y el delegado en el init, además de hacer que el storyboard haga la mitad del trabajo y te deje sin saber que queda otro 1/2 del trabajo por hacer. > 1 hora desperdiciada en esto. –

+0

Esto funciona muy bien para mostrar la leyenda inmediatamente después de la caída del pin. Sin la demora, ves que la leyenda cae con el alfiler, lo que parece extraño. Es desafortunado que se llame "didAddAnnotationViews" en el momento en que el pin comienza a caer, no en el momento en que cae. –

4

El problema con llamar selectAnnotation de - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView es que, como su nombre lo indica, este evento sólo se activa una vez que su cargas MapView inicialmente, por lo que no será capaz de desencadenar la llamada de la anotación si se agrega después de la MapView tiene terminado de cargar

El problema al llamarlo desde - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views es que su anotación puede no aparecer en la pantalla cuando se llama a selectAnnotation, lo que causaría que no tenga ningún efecto.Incluso si centra la región de MapView en la coordenada de la anotación antes de agregar la anotación, bastará con demorar ligeramente la configuración de la región de MapView para llamar a selectAnnotation antes de que la anotación sea visible en la pantalla, especialmente si anima setRegion.

Algunas personas han resuelto este problema llamando selectAnnotation después de un retraso como tal:

-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views { 
    [self performSelector:@selector(selectLastAnnotation) 
     withObject:nil afterDelay:1]; 
} 

-(void)selectLastAnnotation { 
    [myMapView selectAnnotation: 
     [[myMapView annotations] lastObject] animated:YES]; 
} 

Pero incluso entonces puede obtener resultados extraños, ya que puede tomar más de un segundo para que aparezca en pantalla la anotación dependiendo de varios factores, como la distancia entre la región anterior de MapView y la nueva o la velocidad de su conexión a Internet.

decidí hacer la llamada desde - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated lugar ya que garantiza la anotación es en realidad en pantalla (suponiendo que se establece regional de su MapView a su anotación de coordenadas), ya que este evento se desencadena despuéssetRegion (y su animación) tiene terminado. Sin embargo, regionDidChangeAnimated se activa cada vez que cambia la región de su MapView, incluso cuando el usuario simplemente navega alrededor del mapa, por lo que debe asegurarse de tener una condición para identificar correctamente cuándo es el momento adecuado para activar la llamada de la anotación.

Así es como lo hice:

MKPointAnnotation *myAnnotationWithCallout; 

- (void)someMethod { 
    MKPointAnnotation *myAnnotation = [[MKPointAnnotation alloc] init]; 
    [myAnnotation setCoordinate: someCoordinate]; 
    [myAnnotation setTitle: someTitle]; 

    MKCoordinateRegion someRegion = 
     MKCoordinateRegionMakeWithDistance (someCoordinate, zoomLevel, zoomLevel); 

    myAnnotationWithCallout = myAnnotation; 
    [myMapView setRegion: someRegion animated: YES]; 
    [myMapView addAnnotation: myAnnotation]; 
} 

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated 
{ 
    if (myAnnotationWithCallout) 
    { 
     [mapView selectAnnotation: myAnnotationWithCallout animated:YES]; 
     myAnnotationWithCallout = nil; 
    } 
} 

De esa manera su anotación se garantiza que sea en pantalla en el momento selectAnnotation se llama, y ​​la parte if (myAnnotationWithCallout) asegura ajuste distinto de aquel en el - (void)someMethod ninguna región se activa la llamada.

0

Restablecer las anotaciones también traerá la leyenda al frente.

[mapView removeAnnotation: currentMarker]; 
    [mapView addAnnotation:currentMarker]; 
0

Sólo tiene que añadir [MAPview selectAnnotation: punto animado: YES];

Cuestiones relacionadas