Gestes aux sous-vues et MKMapView dans iOS – iOS de base

J'ai une configuration suivante:

mainViewController OverlayView - UIView mapView - MKMapView 

Mon OverlayView est affiché sur mapView et répond à UIPanGestureRecognizer

Maintenant, parce que OverlayView est au-dessus de MapView, je ne peux pas get le pincement pour zoomer sur la fonctionnalité de MapView pour fonctionner.

Que dois-je faire pour que mapView réagisse au pincement et OverLayView réagisse à Pan (comme c'est le cas maintenant)?

La solution que j'ai maintenant consiste simplement à implémenter la fonctionnalité pinch2zoom dans le mainViewController afin qu'il ajuste mapView en conséquence, mais il est beaucoup less lisse que l'implémentation originale d'Apple.

Si vous avez une vue qui est censée être devant MKMapView et ne bouge pas à l'écran lorsque la carte se déplace en dessous, vous devez l'implémenter comme vous l'avez décrit, comme une vue séparée devant (c.-à-d. ) l'affichage de la carte. Mais plutôt que de voir cette vue de face gérer les gestes et d'essayer de modifier la vue de la carte par programme, vous devez simplement définir le userInteractionEnabled sur NO pour cette vue frontale (vous pouvez le faire par programmation ou via Interface Builder). Cela permettra à la vue de la carte derrière elle de recevoir les touches.

Si vous avez des controls sur cette vue de face qui doivent accepter l'interaction de l'user, alors allez-y et activez l'interaction user pour ces quelques controls, mais assurez-vous que la majeure partie de cette vue frontale est configurée pour ne pas userInteractionEnabled .


Si vous voulez une superposition qui devrait se déplacer avec la carte, vous devez simplement append la superposition à MKMapView , elle-même, et non une vue séparée. Voir Affichage des superpositions sur une carte dans le Guide de programmation Awareness. Si vous utilisez des superpositions MKMapView au lieu d'une vue séparée, vous ne perdez aucun des gestes embeddeds.

Par exemple, si vous définissez le delegate pour votre MKMapView comme controller de vue, vous pouvez alors écrire un rendererForOverlay dans iOS 7 (ou la méthode viewForOverlay pour les versions antérieures):

 // for iOS7+; see `viewForOverlay` for earlier versions - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { if ([overlay isKindOfClass:[MKPolygon class]]) { MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:overlay]; renderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2]; renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; renderer.lineWidth = 3; return renderer; } if ([overlay isKindOfClass:[MKCircle class]]) { MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:overlay]; renderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2]; renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; renderer.lineWidth = 3; return renderer; } if ([overlay isKindOfClass:[MKPolyline class]]) { MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay]; renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; renderer.lineWidth = 3; return renderer; } return nil; } // for iOS versions prior to 7; see `rendererForOverlay` for iOS7 and later - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay { if ([overlay isKindOfClass:[MKPolygon class]]) { MKPolygonView *overlayView = [[MKPolygonView alloc] initWithPolygon:overlay]; overlayView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2]; overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; overlayView.lineWidth = 3; return overlayView; } if ([overlay isKindOfClass:[MKCircle class]]) { MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:overlay]; overlayView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2]; overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; overlayView.lineWidth = 3; return overlayView; } if ([overlay isKindOfClass:[MKPolyline class]]) { MKPolylineView *overlayView = [[MKPolylineView alloc] initWithPolyline:overlay]; overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; overlayView.lineWidth = 3; return overlayView; } return nil; } 

Cela gère les polygones, les cercles et les lignes. Il est clair que si vous dessinez uniquement des polygones, par exemple, vous pouvez simplifier le code ci-dessus en conséquence.

Une fois que vous faites cela, vous pouvez maintenant append une superposition directement sur la carte. Par exemple, cela ajoute une superposition qui est un rectangle d'une certaine taille autour d'une coordonnée particulière:

 - (void)addOverlayAround:(CLLocationCoordinate2D)originalCoordinate atDistance:(double)distanceKm { MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(originalCoordinate, distanceKm * 1000.0 * 2.0, distanceKm * 1000 * 2.0); MKCoordinateSpan span = region.span; CLLocationCoordinate2D points[4]; points[0] = CLLocationCoordinate2DMake(originalCoordinate.latitude + span.latitudeDelta / 2.0, originalCoordinate.longitude - span.longitudeDelta / 2.0); points[1] = CLLocationCoordinate2DMake(originalCoordinate.latitude + span.latitudeDelta / 2.0 , originalCoordinate.longitude + span.longitudeDelta / 2.0); points[2] = CLLocationCoordinate2DMake(originalCoordinate.latitude - span.latitudeDelta / 2.0, originalCoordinate.longitude + span.longitudeDelta / 2.0); points[3] = CLLocationCoordinate2DMake(originalCoordinate.latitude - span.latitudeDelta / 2.0, originalCoordinate.longitude - span.longitudeDelta / 2.0); MKPolygon* poly = [MKPolygon polygonWithCoordinates:points count:4]; if ([self.mapView respondsToSelector:@selector(addOverlay:level:)]) [self.mapView addOverlay:poly level:MKOverlayLevelAboveLabels]; else [self.mapView addOverlay:poly]; // // If you want to draw a circle around the coordinate, instead, you could do something like: // // MKCircle *circle = [MKCircle circleWithCenterCoordinate:originalCoordinate radius:distanceKm * 1000.0 * sqrt(2.0)]; // if ([self.mapView respondsToSelector:@selector(addOverlay:level:)]) // [self.mapView addOverlay:circle level:MKOverlayLevelAboveLabels]; // else // [self.mapView addOverlay:circle]; // // if you want to draw some lines, you could do something like: // // MKPolyline *polyline = [MKPolyline polylineWithCoordinates:points count:4]; // if ([self.mapView respondsToSelector:@selector(addOverlay:level:)]) // [self.mapView addOverlay:polyline level:MKOverlayLevelAboveLabels]; // else // [self.mapView addOverlay:polyline]; self.mapView.delegate = self; } 

Je ne sais pas si ce que je vais proposer peut fonctionner ou si c'est une bonne solution, de toute façon c'est l'idée

Définissez votre MainViewController en tant que délégué pour les reconnaisseurs de mouvements

 -(BOOL)gestureRecognizer:(UIGestureRecognizer*)gr shouldReceiveTouch:(UITouch*)touch{ if([gr isKindOfClass:[UIPanGestureRecognizer class]]) [mapView setUserInteractionEnabled:NO]; else if([gr isKindOfClass:[UIPinchGestureRecognizer class]]) [overlayView setUserInteractionEnabled:YES]; return YES; }