web-dev-qa-db-fra.com

MKMapView MKPointAnnotation événement tap

J'ai une liste d'annotations (MKPointAnnotation). J'ai un UIViewController qui est pour toute la vue, MKMapView implémentant un contrôleur, ce qui m'a semblé utile pour détecter l'interaction des utilisateurs avec la carte, mon propre contrôleur MKPointAnnotation implémentant (sous-classe) qui indique comment afficher l'annotation.

Cependant, je suis frappé par la détection de l'événement tap par l'utilisateur.

Googling m'a dit que je devais faire quelque chose en implémentant la fonction suivante.

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control

et aussi que je dois implémenter ceci dans une classe qui implémente le MapViewDelegate (Protocol).

Mais je suis tout confus et incapable d'avancer. Quelqu'un peut-il me dire où faire quoi?

Désolé pour tout le tapage!

46
Ravi Vooda

Il existe deux manières de détecter une interaction de l'utilisateur avec votre vue d'annotation. La technique courante consiste à définir une légende (cette petite bulle de popover standard que vous voyez lorsque vous appuyez sur une épingle dans une application cartographique typique) pour votre MKAnnotationView. Et vous créez la vue d'annotation pour votre annotation dans la méthode standard viewForAnnotation:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;

    MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
    annotationView.canShowCallout = YES;
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

    return annotationView;
}

En faisant cela, vous obtenez une légende, mais vous ajoutez un accessoire approprié, qui est, dans mon exemple ci-dessus, un indicateur de divulgation. De cette façon, ils appuieront sur votre vue d'annotation (dans mon exemple ci-dessus, une épingle sur la carte), ils verront la légende, et lorsqu'ils appuieront sur le bon accessoire de cette légende (le petit indicateur de divulgation dans cet exemple), votre calloutAccessoryControlTapped est appelé (dans mon exemple ci-dessous, effectuant une transition vers un contrôleur de vue de détail):

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
    [self performSegueWithIdentifier:@"DetailsIphone" sender:view];
}

C'est une expérience utilisateur très typique sur le petit écran de l'iPhone.

Mais si vous n'aimez pas cette UX et que vous ne voulez pas la légende standard, mais plutôt que quelque chose d'autre se passe, vous pouvez définir votre MKAnnotationView de sorte qu'une légende ne soit pas affichée, mais vous interceptez-le et faites quelque chose d'autre (par exemple, sur les applications de cartes iPad, vous pouvez afficher une popover plus sophistiquée que la légende standard). Par exemple, vous pourriez que votre MKAnnotationView ne montre pas de légende:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;

    MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
    annotationView.canShowCallout = NO;

    return annotationView;
}

Mais vous pouvez alors gérer manuellement didSelectAnnotationView pour détecter quand un utilisateur a tapé sur votre MKAnnotationView, dans cet exemple montrant un popover:

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
    [mapView deselectAnnotation:view.annotation animated:YES];

    DetailsViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DetailsPopover"];
    controller.annotation = view.annotation;
    self.popover = [[UIPopoverController alloc] initWithContentViewController:controller];
    self.popover.delegate = self;
    [self.popover presentPopoverFromRect:view.frame
                                  inView:view.superview
                permittedArrowDirections:UIPopoverArrowDirectionAny
                                animated:YES];
}

J'inclus quelques captures d'écran de l'interface utilisateur générées par le code ci-dessus dans ma réponse ici .

104
Rob

Exemple Robs pour Swift 3:

class MapViewController: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()

        // Create map view in storyboard
        view.delegate = self
    }
}

extension MapViewController: MKMapViewDelegate
{
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
    {
        let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "annotationView")
        annotationView.canShowCallout = true
        annotationView.rightCalloutAccessoryView = UIButton.init(type: UIButtonType.detailDisclosure)

        return annotationView
    }

    func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl)
    {
        guard let annotation = view.annotation else
        {
            return
        }

        let urlString = "http://maps.Apple.com/?sll=\(annotation.coordinate.latitude),\(annotation.coordinate.longitude)"
        guard let url = URL(string: urlString) else
        {
            return
        }

        UIApplication.shared.openURL(url)
    }
}
8
RhodanV5500

Bouton Ajouter dans cette méthode

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation 
{
  pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
  pinView.canShowCallout = YES;
}

Then callout method
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
      InfoView *infoView = [[InfoView alloc]initWithNibName:@"InfoView" bundle:nil];
        [self.navigationController pushViewController:infoView animated:YES];

} 
5
Bajaj