30 votes

Wanted : Comment sélectionner de manière fiable et cohérente une annotation MKMapView ?

Après avoir appelé MKMapView 's setCenterCoordinate:animé : (sans animation), j'aimerais appeler la méthode selectAnnotation:animated : (avec animation) pour que l'annotation sorte de la punaise nouvellement centrée.

Pour l'instant, je me contente de guetter mapViewDidFinishLoadingMap : puis sélectionnez l'annotation. Cependant, cette méthode pose des problèmes. Par exemple, cette méthode n'est pas appelée lorsqu'il n'est pas nécessaire de charger des données cartographiques supplémentaires. Dans ce cas, mon annotation n'est pas sélectionnée. :(

Très bien. Je pourrais l'appeler immédiatement après avoir défini la coordonnée centrale. Ahh, mais dans ce cas, il est possible qu'il y ait un es les données de la carte à charger (mais le chargement n'est pas encore terminé). Je risquerais de l'appeler trop tôt, ce qui rendrait l'animation au mieux irrégulière.

Ainsi, si je comprends bien, il ne s'agit pas de savoir si ma coordonnée est visible, puisqu'il est possible de s'éloigner de près d'un écran et de devoir charger de nouvelles données cartographiques. Plutôt, il s'agit de savoir si de nouvelles données cartographiques doivent être chargées et d'agir en conséquence.

Avez-vous des idées sur la manière d'y parvenir ou sur la manière de sélectionner une annotation après avoir recentré la vue de la carte sur la coordonnée où se trouve cette annotation ?

Les indices sont les bienvenus - merci !

36voto

John Blackburn Points 356

J'ai rencontré le même problème, mais j'ai trouvé ce qui semble être une solution fiable et raisonnable :

  1. Implémenter la méthode déléguée mapView:didAddAnnotationViews :. Lorsque j'ai essayé de sélectionner l'annotation directement dans la méthode déléguée, le callout est tombé avec l'épingle ! Cela semblait étrange, et j'ai donc ajouté un léger délai d'une demi-seconde.

    -(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
        [self performSelector:@selector(selectInitialAnnotation)
              withObject:nil afterDelay:0.5];
    }
  2. Sélectionnez l'annotation initiale comme vous vous y attendez, mais en appelant selectAnnotation:animated ;

    -(void)selectInitialAnnotation {
        [self.mapView selectAnnotation:self.initialAnnotation animated:YES];
    }

Il semble que selectAnnotation:animated: n'est pas appelé dans certaines conditions. Comparer avec MKMapView docs :

Si l'annotation spécifiée n'est pas n'a pas de vue d'annotation associée, cette méthode n'a aucun effet.

7voto

Anurag Points 66470

Une méthode plus cohérente que l'utilisation d'un délai d'attente fixe consiste à écouter la commande regionDidChange rappel. Définissez la coordonnée centrale de la carte sur l'annotation souhaitée et, lorsque la méthode regionDidChange est appelée, sélectionnez l'annotation au centre pour ouvrir le callout.

Voici un peu vidéo J'ai pris une photo de l'appareil fonctionnant aléatoirement entre 5 broches.

Tout d'abord, obtenez la coordonnée centrale de l'annotation. Supposons que l'objet d'annotation s'appelle thePin .

- (void)someMethod {
    [map setCenterCoordinate:thePin.coordinate animated:YES];
}

Ensuite, dans le regionDidChange sélectionnez cette annotation.

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
    [map selectAnnotation:thePin animated:YES];
}

5voto

akshaynhegde Points 781

Pour information, voici ce que disent les médecins,

Si l'annotation spécifiée n'est pas à l'écran, et n'est donc pas n'a pas de vue d'annotation associée, cette méthode n'a aucun effet.

Ainsi, si je veux appeler setCenterCoordinate:animated: o setRegion:animated: et ensuite je veux sélectionner l'annotation en appelant , selectAnnotation:animated: L'annotation ne sera pas sélectionnée et le callout n'apparaîtra pas pour la même raison que celle mentionnée dans la documentation, setCenterCoordinate:animated:ComletionBlock mais il n'est pas là ! La méthode qui a fonctionné pour moi est la suivante,

 [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.mapView setCenterCoordinate:location.coordinate animated:YES];
    } completion:^(BOOL finished) {
        [self.mapView selectAnnotation:location animated:YES];
    }];

Vous obtiendrez un bloc d'achèvement que vous pourrez utiliser pour sélectionner l'annotation.

4voto

szzsolt Points 489

Ce qui a fonctionné pour moi, c'est d'appeler selectAnnotation:animated: de la mapView:didAddAnnotationViews: méthode :

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

Documentation d'Apple sur le même sujet aquí .

Notez que je n'avais qu'une seule annotation sur la carte. [[mapView annotations] lastObject] était très bien pour mes besoins. Votre kilométrage peut varier.

2voto

Justin Kent Points 148

J'ai eu un problème similaire. J'utilisais la MKPinAnnotationView par défaut avec animatesDrop:YES. Après avoir ajouté les annotations à la MKMapView, je faisais ceci :

[mapView selectAnnotation:[mapView.annotations objectAtIndex:1] animated:YES]

qui, dans la logique de mon programme, devrait sélectionner l'annotation la plus proche. Cela ne fonctionnait pas. J'en ai trouvé la raison : la vue de l'annotation n'était pas à l'écran au moment de l'appel à la sélection, à cause de l'animation de la chute de l'épingle. Tout ce que j'ai fait, c'est de programmer une minuterie pour sélectionner l'annotation une seconde plus tard. C'est une astuce, mais ça marche. Je ne suis pas sûr que cela fonctionne dans toutes les situations, par exemple sur une 3G ou une 3Gs. Il serait préférable de trouver la bonne fonction de rappel pour l'intégrer.

selectTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self
               selector:@selector(selectClosestAnnotation) userInfo:nil
               repeats:NO];

- (void)selectClosestAnnotation {
    [mapView selectAnnotation:[mapView.annotations objectAtIndex:1]
             animated:YES];
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X