2012-08-06 21 views
21

El scrollEnabled parece ser frágil una vez que el usuario comienza a pellizcar en un MKMapView.Impedir el desplazamiento en un MKMapView, también al hacer zoom

Aún no puede desplazarse con un dedo, pero si se desplaza con dos dedos mientras acerca o aleja la imagen, puede mover el mapa.

que he intentado:

  • subclases de la MKMapKit desactivar la vista de desplazamiento en su interior.
  • Implementación - mapView:regionWillChangeAnimated: para aplicar el centro.
  • Deshabilitando scrollEnabled.

pero sin suerte.

¿Alguien puede decirme una manera segura de tener SOLAMENTE el acercamiento en un MKMapView, entonces el punto central siempre permanece en el medio?

+2

He tenido que hacer esto antes pero lo manejé de otra manera. Inhabilité la interacción con MKMapView y agregué reconocimientos de gestos de pellizco a una vista superior. Luego convertí los gestos de pellizco en un nivel de zoom correspondiente. Así que basta con rodar tu propio pellizco para hacer zoom funcionalmente. Al ver que esto no responde directamente a su pregunta, si es una opción viable para usted, la publicaré en las respuestas con el código. – random

Respuesta

29

Usted puede tratar de manejar los gestos de pellizco por sí mismo utilizando un UIPinchGestureRecognizer:

Primero ajuste scrollEnabled y zoomEnabled a NO y crear el reconocedor gesto:

UIPinchGestureRecognizer* recognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self 
                       action:@selector(handlePinch:)]; 
[self.mapView addGestureRecognizer:recognizer]; 

En el controlador reconocedor ajustar el MKCoordinateSpan según la escala de zoom:

- (void)handlePinch:(UIPinchGestureRecognizer*)recognizer 
{ 
    static MKCoordinateRegion originalRegion; 
    if (recognizer.state == UIGestureRecognizerStateBegan) { 
     originalRegion = self.mapView.region; 
    }  

    double latdelta = originalRegion.span.latitudeDelta/recognizer.scale; 
    double londelta = originalRegion.span.longitudeDelta/recognizer.scale; 

    // TODO: set these constants to appropriate values to set max/min zoomscale 
    latdelta = MAX(MIN(latdelta, 80), 0.02); 
    londelta = MAX(MIN(londelta, 80), 0.02); 
    MKCoordinateSpan span = MKCoordinateSpanMake(latdelta, londelta); 

    [self.mapView setRegion:MKCoordinateRegionMake(originalRegion.center, span) animated:YES]; 
} 

Este puede no funcionar perfectamente como la implementación de Apple, pero debería resolver su problema.

+1

No creo que esta solución sea tan buena. Se siente muy torpe en comparación con el zoom predeterminado proporcionado por Apple. Por ejemplo, hay un desfase entre el pellizco y la actualización de la pantalla. –

+0

esto no funciona en absoluto. – Haitao

+0

cambio animado: SÍ a animado: No en la última línea [self.mapView setRegion: MKCoordinateRegionMake (originalRegion.center, span) animated: YES]; y funciona sin problemas. –

1

Intente implementar –mapView:regionWillChangeAnimated: o –mapView:regionDidChangeAnimated: en el delegado de su vista de mapa para que el mapa esté siempre centrado en su ubicación preferida.

+0

Probado ... Esto no tiene ningún efecto. –

1

He leído sobre esto antes, aunque nunca lo he probado. Eche un vistazo a este artículo sobre un MKMapView con límites. Utiliza dos métodos delegados para verificar si la vista ha sido desplazada por el usuario.

http://blog.jamgraham.com/blog/2012/04/29/adding-boundaries-to-mkmapview

El artículo describe un enfoque que es similar a lo que ha intentado, por lo que, lo siento si ya ha tropezado con él.

1

No tuve mucha suerte con ninguna de estas respuestas. Hacer mi propio pellizco simplemente entró en conflicto demasiado. Me encontré con casos en los que el zoom normal se acercaba más de lo que podía hacer con mi propio pellizco.

Originalmente, traté como el cartel original de hacer algo como:

- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { 
    MKCoordinateRegion region = mapView.region; 
    //... 
    // adjust the region.center 
    //... 
    mapView.region = region; 
} 

Lo que encontré fue que eso no tuvo ningún efecto. También descubrí a través de NSLog s que este método se activará incluso cuando configuro el region o el centerCoordinate programáticamente. Lo que llevó a la pregunta: "¿No sería lo anterior, si funcionara, llegar a ser infinito?"

Así que estoy haciendo conjeturas y hacer hipótesis ahora que mientras que el usuario de zoom/desplazamiento/rotación está sucediendo, MapView alguna manera suprime o ignora los cambios en la región. Algo sobre el arbitraje hace que el ajuste programático impotente.

Si eso es el problema, entonces tal vez la clave es obtener el ajuste de la región fuera de la notificación regionDidChanged:. Y dado que cualquier ajuste desencadenará otra notificación, es importante que pueda determinar cuándo no se debe ajustar más. Esto me llevó a la siguiente implementación (donde subject está suministrando la coordenada central que quiero permanecer en el medio):

- (void) recenterMap { 
    double latDiff = self.subject.coordinate.latitude self.mapView.centerCoordinate.latitude; 
    double lonDiff = self.subject.coordinate.longitude - self.mapView.centerCoordinate.longitude; 
    BOOL latIsDiff = ABS(latDiff) > 0.00001; 
    BOOL lonIsDiff = ABS(lonDiff) > 0.00001; 
    if (self.subject.isLocated && (lonIsDiff || latIsDiff)) { 
     [self.mapView setCenterCoordinate: self.subject.coordinate animated: YES]; 
    } 
} 

- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { 
    if (self.isShowingMap) { 
     if (self.isInEdit) { 
      self.setLocationButton.hidden = NO; 
      self.mapEditPrompt.hidden = YES; 
     } 
     else { 
      if (self.subject.isLocated) { // dispatch outside so it will happen after the map view user events are done 
       dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^{ 
        [self recenterMap]; 
       }); 
      } 
     } 
    } 
} 

La demora en la que se desliza hacia atrás puede variar, pero realmente funciona bastante bien. Y permite que la interacción del mapa siga siendo al estilo de Apple mientras está sucediendo.

1

Intenté esto y funciona.

En primer lugar crear una propiedad:

var originalCenter: CLLocationCoordinate2D? 

Luego, en regionWillChangeAnimated, comprobar si este evento es causado por un UIPinchGestureRecognizer:

func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) { 
    let firstView = mapView.subviews.first 
    if let recognizer = firstView?.gestureRecognizers?.filter({ $0.state == .Began || $0.state == .Ended }).first as? UIPinchGestureRecognizer { 
     if recognizer.scale != 1.0 { 
      originalCenter = mapView.region.center 
     } 
    } 
} 

Luego, en regionDidChangeAnimated, volver a la región original si un gesto de pellizco causado el cambio de región:

func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) { 
    if let center = originalCenter { 
     mapView.setRegion(MKCoordinateRegion(center: center, span: mapView.region.span), animated: true) 
     originalCenter = nil 
     return 
    } 
// your other code 
} 
1

Swift 3.0 versión de @Paras Joshi respuesta https://stackoverflow.com/a/11954355/3754976

con la corrección de animación pequeña.

class MapViewZoomCenter: MKMapView { 

    var originalRegion: MKCoordinateRegion! 

    override func awakeFromNib() { 
     self.configureView() 
    } 

    func configureView() { 
     isZoomEnabled = false 
     self.registerZoomGesture() 
    } 

    ///Register zoom gesture 
    func registerZoomGesture() { 
     let recognizer = UIPinchGestureRecognizer(target: self, action:#selector(MapViewZoomCenter.handleMapPinch(recognizer:))) 
     self.addGestureRecognizer(recognizer) 
    } 

    ///Zoom in/out map 
    func handleMapPinch(recognizer: UIPinchGestureRecognizer) { 

     if (recognizer.state == .began) { 
      self.originalRegion = self.region; 
     } 

     var latdelta: Double = originalRegion.span.latitudeDelta/Double(recognizer.scale) 
     var londelta: Double = originalRegion.span.longitudeDelta/Double(recognizer.scale) 

     //set these constants to appropriate values to set max/min zoomscale 
     latdelta = max(min(latdelta, 80), 0.02); 
     londelta = max(min(londelta, 80), 0.02); 

     let span = MKCoordinateSpanMake(latdelta, londelta) 

     self.setRegion(MKCoordinateRegionMake(originalRegion.center, span), animated: false) 

    } 
} 
Cuestiones relacionadas