web-dev-qa-db-fra.com

Comment capturer le geste Tap sur MKMapView

J'essaie de capturer l'événement tap sur ma MKMapView, de cette façon je peux déposer une MKPinAnnotation sur le point où l'utilisateur a tapé. Fondamentalement, j'ai une carte recouverte de MKOverlayViews (une superposition montrant un bâtiment) et je voudrais donner à l'utilisateur plus d'informations à propos de cette superposition lorsqu'il appuie dessus en déposant une MKPinAnnotaion et en montrant plus d'informations dans la légende. vous. 

31
sbkb

Vous pouvez utiliser une UIGestureRecognizer pour détecter les contacts sur la vue cartographique.

Cependant, au lieu d’un simple tapotement, je suggère de chercher un tapotement double (UITapGestureRecognizer) ou un appui long (UILongPressGestureRecognizer). Une simple pression peut interférer avec l'utilisateur qui tente de toucher la broche ou la légende elle-même.

À l’endroit où vous avez configuré la vue Carte (dans viewDidLoad par exemple), attachez le dispositif de reconnaissance de mouvements à la vue Carte:

UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] 
    initWithTarget:self action:@selector(handleGesture:)];
tgr.numberOfTapsRequired = 2;
tgr.numberOfTouchesRequired = 1;
[mapView addGestureRecognizer:tgr];
[tgr release];

ou pour utiliser un appui long:

UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] 
    initWithTarget:self action:@selector(handleGesture:)];
lpgr.minimumPressDuration = 2.0;  //user must press for 2 seconds
[mapView addGestureRecognizer:lpgr];
[lpgr release];


Dans la méthode handleGesture::

- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
        return;

    CGPoint touchPoint = [gestureRecognizer locationInView:mapView];
    CLLocationCoordinate2D touchMapCoordinate = 
        [mapView convertPoint:touchPoint toCoordinateFromView:mapView];

    MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
    pa.coordinate = touchMapCoordinate;
    pa.title = @"Hello";
    [mapView addAnnotation:pa];
    [pa release];
}
59
user467105

J'installe un appui long (UILongPressGestureRecognizer) dans viewDidLoad: mais il ne détecte que le seul contact du premier.

Où puis-je configurer un appui long pour détecter tout contact? (cela signifie que la carte est prête à chaque fois que l'utilisateur attend de toucher l'écran pour pousser une broche)

La méthode viewDidLoad:!

- (void)viewDidLoad {
    [super viewDidLoad];mapView.mapType = MKMapTypeStandard;

    UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)];
    [self.mapView addGestureRecognizer:longPressGesture];
    [longPressGesture release];

    mapAnnotations = [[NSMutableArray alloc] init];
    MyLocation *location = [[MyLocation alloc] init];
    [mapAnnotations addObject:location];

    [self gotoLocation];
    [self.mapView addAnnotations:self.mapAnnotations];
}

et la méthode handleLongPressGesture:

-(void)handleLongPressGesture:(UIGestureRecognizer*)sender {
    // This is important if you only want to receive one tap and hold event
    if (sender.state == UIGestureRecognizerStateEnded)
    {NSLog(@"Released!");
        [self.mapView removeGestureRecognizer:sender];
    }
    else
    {
        // Here we get the CGPoint for the touch and convert it to latitude and longitude coordinates to display on the map
        CGPoint point = [sender locationInView:self.mapView];
        CLLocationCoordinate2D locCoord = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
        // Then all you have to do is create the annotation and add it to the map
        MyLocation *dropPin = [[MyLocation alloc] init];
        dropPin.latitude = [NSNumber numberWithDouble:locCoord.latitude];
        dropPin.longitude = [NSNumber numberWithDouble:locCoord.longitude];
//        [self.mapView addAnnotation:dropPin];
        [mapAnnotations addObject:dropPin];
        [dropPin release];
        NSLog(@"Hold!!");
        NSLog(@"Count: %d", [mapAnnotations count]);
    }   
}
5
o0oKodako0o

Si vous souhaitez utiliser un simple clic/tap dans la vue Carte, voici un extrait de code que j'utilise. (Cacao et Swift)

let gr = NSClickGestureRecognizer(target: self, action: "createPoint:")
gr.numberOfClicksRequired = 1
gr.delaysPrimaryMouseButtonEvents = false // allows +/- button press
gr.delegate = self
map.addGestureRecognizer(gr)

dans la méthode des délégués de geste, un test simple pour préférer le geste de double frappe…

func gestureRecognizer(gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: NSGestureRecognizer) -> Bool {
  let other = otherGestureRecognizer as? NSClickGestureRecognizer
  if (other?.numberOfClicksRequired > 1) {
    return true; // allows double click
  }

  return false
}

vous pouvez également filtrer le geste dans d'autres méthodes de délégation si vous souhaitez que la carte se trouve dans différents "états", l'un d'eux autorisant le clic/clic unique.

2
bshirley

Pour une raison quelconque, le UIGestureRecognizer ne fonctionnait tout simplement pas pour moi à Swift. Lorsque j'utilise la méthode UIGestureRecognizer. Lorsque j'ai utilisé la méthode touchesEnded, il renvoie un MKNewAnnotationContainerView. Il semble que ce MKNewAnnotationContainerView a bloqué mon MKMapView. Heureusement, c'est une sous-vue de MKMapView. J'ai donc parcouru les superviews de MKNewAnnotationContainerView jusqu'à self.view pour obtenir MKMapView. Et j'ai réussi à épingler la carte en tapotant. 

Swift 4.1

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    let t = touches.first
    print(t?.location(in: self.view) as Any)
    print(t?.view?.superview?.superview.self as Any)
    print(mapView.self as Any)
    var tempView = t?.view
    while tempView != self.view {
        if tempView != mapView {
            tempView = tempView?.superview!
        }else if tempView == mapView{
            break
        }

    }
  let convertedCoor = mapView.convert((t?.location(in: mapView))!, toCoordinateFrom: mapView)
   let pin =  MKPointAnnotation()
    pin.coordinate = convertedCoor
    mapView.addAnnotation(pin)
}
0
William Tong