iOS: ¿cómo limitar el MapView a una región específica?

Tengo el siguiente problema:

Tengo un “mapa dibujado” (imagen) que agrego a MapView como una Superposición. No hay problema con eso … pero tengo que limitar el MapView a la región de la Superposición, por lo que un usuario no puede desplazarse / alejarse fuera de esta región … pero debería ser posible desplazarse / acercarse a los “límites”. “de la superposición” significa que no puedo deshabilitar el zoom / desplazamiento para MapView.

¿Hay alguna idea / solución sobre este tema? La razón para usar MapView / -Kit es que necesito agregar varios POI al mapa personalizado. Esto puede volverse más complejo cuando solo se usa ImageView + ScrollView para presentar el mapa personalizado.

Investigué mucho sobre este tema, pero no encontré una buena solución.

¡Cualquier ayuda es apreciada!

Saludos, Christian

Editar: Esta es nuestra solución: proporciona una coordenada topleft y una coordenada inferior para limitar el mapa. El nivel de zoom (mínimo) también es limitado. Desactivé la desaceleración y puedes saltar un poco fuera del mapa (para un mejor rendimiento / ux). Agregué un borde gris de ~ 1km a la superposición para que el usuario no pueda ver el mapa mundial orignal de google.

LimitedMapView.h:

#import  #import  @interface LimitedMapView : MKMapView { } @property (nonatomic, assign) CLLocationCoordinate2D topLeftCoordinate; @property (nonatomic, assign) CLLocationCoordinate2D bottomRightCoordinate; @end 

LimitedMapView.m:

 #import "LimitedMapView.h" @implementation LimitedMapView @synthesize topLeftCoordinate, bottomRightCoordinate; - (void)scrollViewDidZoom:(UIScrollView *)scrollView{ if([super respondsToSelector:@selector(scrollViewDidZoom:)]) [super scrollViewDidZoom:scrollView]; if ([self region].span.latitudeDelta > 0.002401f || [self region].span.longitudeDelta > 0.003433f) { CLLocationCoordinate2D center = self.centerCoordinate; MKCoordinateSpan span = MKCoordinateSpanMake(0.002401f, 0.003433f); self.region = MKCoordinateRegionMake(center, span); } } -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ if([super respondsToSelector:@selector(scrollViewDidEndDragging:)]) [super scrollViewDidEndDragging:scrollView willDecelerate:decelerate]; MKCoordinateRegion currentRegion = self.region; bool changeRegionLong = YES; bool changeRegionLat = YES; // LONGITUDE if((currentRegion.center.longitude - (currentRegion.span.longitudeDelta/2))  self.bottomRightCoordinate.longitude) { currentRegion.center.longitude = (bottomRightCoordinate.longitude - (currentRegion.span.longitudeDelta/2)); } else { changeRegionLong = NO; } // LATITUDE if((currentRegion.center.latitude + (currentRegion.span.latitudeDelta/2)) > self.topLeftCoordinate.latitude) { currentRegion.center.latitude = (topLeftCoordinate.latitude - (currentRegion.span.latitudeDelta/2)); } else if((currentRegion.center.latitude - (currentRegion.span.latitudeDelta/2)) < self.bottomRightCoordinate.latitude) { currentRegion.center.latitude = (bottomRightCoordinate.latitude + (currentRegion.span.latitudeDelta/2)); } else { changeRegionLat = NO; } if(changeRegionLong || changeRegionLat) [self setRegion:currentRegion animated:YES]; } -(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{ [scrollView setContentOffset:scrollView.contentOffset animated:YES]; } @end 

Al implementar:

-(void) mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated

Debería poder restablecer la región a su región específica.

Mire esa respuesta para tener un ejemplo de cómo hacer esto.


Otra solución, que trae eventos más precisos pero es más compleja (actualmente estoy usando esto con éxito para otra necesidad) es subclasificar MKMapView y anular el protocolo UIScrollViewDelegate .

Si lo haces, asegúrate de llamar super implementación así:

 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { if ([super respondsToSelector:@selector(scrollViewWillBeginDragging:)]) [super scrollViewWillBeginDragging:scrollView]; // do what you want } 

Nota: Si bien el protocolo es público, la implementación de MKMapView es desconocida y puede diferir con las versiones de iOS, por lo que es más seguro consultar con respondsToSelector: before. Debe llamar a super implementaciones o Map simplemente no funcionará correctamente .

Después de probar diferentes formas de MKMapView limitado, he llegado a la conclusión de que usar mapDidChange y restablecer si tu punto central va fuera de los límites funciona mejor, con animación: SÍ

Así es como lo hago (usando el latín / largo / centro de Nueva Zelanda).

 - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{ if ((mapView.region.span.latitudeDelta > 15.589921 ) || (mapView.region.span.longitudeDelta > 175.836914) ) { CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914); MKCoordinateSpan spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 ); MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ); [mapView setRegion: NZRegion animated: YES]; } if (abs(abs(mapView.region.center.latitude) - 41.162114) > (13.589921 / 2) ) { CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914); MKCoordinateSpan spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 ); MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ); [mapView setRegion: NZRegion animated: YES]; } if (abs(abs(mapView.region.center.longitude) - 172.836914) > (14.062500 / 2) ) { CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914); MKCoordinateSpan spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 ); MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ); [mapView setRegion: NZRegion animated: YES]; } } 

Sé que esta es una pregunta bastante antigua, pero para evitar el ciclo infinito, podrías intentar algo como esto: https://stackoverflow.com/a/4126011/1234011

Básicamente establezca un indicador para evitar que la callback vuelva a activarse si fue usted quien configuró el valor.

  • Conocido