¿Cómo interceptar eventos táctiles en objetos MKMapView o UIWebView?

96

No estoy seguro de qué estoy haciendo mal, pero trato de captar los toques de un MKMapViewobjeto. Lo subclasé creando la siguiente clase:

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface MapViewWithTouches : MKMapView {

}

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event;   

@end

Y la implementación:

#import "MapViewWithTouches.h"
@implementation MapViewWithTouches

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event {

    NSLog(@"hello");
    //[super touchesBegan:touches   withEvent:event];

}
@end

Pero parece que cuando uso esta clase, no veo nada en la consola:

MapViewWithTouches *mapView = [[MapViewWithTouches alloc] initWithFrame:self.view.frame];
[self.view insertSubview:mapView atIndex:0];

¿Alguna idea de lo que estoy haciendo mal?

Martín
fuente

Respuestas:

147

La mejor manera que he encontrado para lograr esto es con un Gesture Recognizer. Otras formas implican una gran cantidad de programación pirateada que duplica imperfectamente el código de Apple, especialmente en el caso de multitouch.

Esto es lo que hago: Implemento un reconocedor de gestos que no se puede prevenir y que no puede evitar otros reconocedores de gestos. Agréguelo a la vista del mapa, y luego use el gestoRecognizer's touchesBegan, touchesMoved, etc. a su gusto.

Cómo detectar cualquier toque dentro de un MKMapView (sin trucos)

WildcardGestureRecognizer * tapInterceptor = [[WildcardGestureRecognizer alloc] init];
tapInterceptor.touchesBeganCallback = ^(NSSet * touches, UIEvent * event) {
        self.lockedOnUserLocation = NO;
};
[mapView addGestureRecognizer:tapInterceptor];

WildcardGestureRecognizer.h

//
//  WildcardGestureRecognizer.h
//  Copyright 2010 Floatopian LLC. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef void (^TouchesEventBlock)(NSSet * touches, UIEvent * event);

@interface WildcardGestureRecognizer : UIGestureRecognizer {
    TouchesEventBlock touchesBeganCallback;
}
@property(copy) TouchesEventBlock touchesBeganCallback;


@end

WildcardGestureRecognizer.m

//
//  WildcardGestureRecognizer.m
//  Created by Raymond Daly on 10/31/10.
//  Copyright 2010 Floatopian LLC. All rights reserved.
//

#import "WildcardGestureRecognizer.h"


@implementation WildcardGestureRecognizer
@synthesize touchesBeganCallback;

-(id) init{
    if (self = [super init])
    {
        self.cancelsTouchesInView = NO;
    }
    return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (touchesBeganCallback)
        touchesBeganCallback(touches, event);
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}

- (void)reset
{
}

- (void)ignoreTouch:(UITouch *)touch forEvent:(UIEvent *)event
{
}

- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
{
    return NO;
}

- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
{
    return NO;
}

@end

SWIFT 3

let tapInterceptor = WildCardGestureRecognizer(target: nil, action: nil)
tapInterceptor.touchesBeganCallback = {
    _, _ in
    self.lockedOnUserLocation = false
}
mapView.addGestureRecognizer(tapInterceptor)

WildCardGestureRecognizer.swift

import UIKit.UIGestureRecognizerSubclass

class WildCardGestureRecognizer: UIGestureRecognizer {

    var touchesBeganCallback: ((Set<UITouch>, UIEvent) -> Void)?

    override init(target: Any?, action: Selector?) {
        super.init(target: target, action: action)
        self.cancelsTouchesInView = false
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        touchesBeganCallback?(touches, event)
    }

    override func canPrevent(_ preventedGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }

    override func canBePrevented(by preventingGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }
}
Gonzojive
fuente
3
¿Para qué sirve "lockOnUserLocation"?
jowie
esa es una variable extraña específica de mi aplicación. realiza un seguimiento de si el sistema debe centrar automáticamente el mapa en la ubicación actual
gonzojive
Ésta es la solución perfecta. Necesito una aclaración: en el método "- (void) touchesBegan: (NSSet *) toca withEvent: (UIEvent *) event", cuál es el propósito de usar el código: if (touchesBeganCallback) touchesBeganCallback (toca, evento);
Satyam
1
Esto funciona muy bien en su mayor parte, pero he encontrado un problema con él. Si el HTML en su vista web contiene una videoetiqueta HTML5 con controles, el reconocedor de gestos evitará que el usuario pueda usar los controles. He estado buscando una solución alternativa para esto, pero todavía tengo que encontrar una.
Bryan Irace
Gracias por compartir. No entiendo por qué no existe un método de delegado adecuado para rastrear las interacciones del usuario con una vista de mapa, pero esto funciona bien.
Justin Driscoll
29

Después de un día de pizzas, gritos, ¡finalmente encontré la solución! ¡Muy aseado!

Peter, utilicé tu truco anterior y lo modifiqué un poco para finalmente tener una solución que funcione perfectamente con MKMapView y debería funcionar también con UIWebView

MKTouchAppDelegate.h

#import <UIKit/UIKit.h>
@class UIViewTouch;
@class MKMapView;

@interface MKTouchAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    UIViewTouch *viewTouch;
    MKMapView *mapView;
}
@property (nonatomic, retain) UIViewTouch *viewTouch;
@property (nonatomic, retain) MKMapView *mapView;
@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

MKTouchAppDelegate.m

#import "MKTouchAppDelegate.h"
#import "UIViewTouch.h"
#import <MapKit/MapKit.h>

@implementation MKTouchAppDelegate

@synthesize window;
@synthesize viewTouch;
@synthesize mapView;


- (void)applicationDidFinishLaunching:(UIApplication *)application {

    //We create a view wich will catch Events as they occured and Log them in the Console
    viewTouch = [[UIViewTouch alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];

    //Next we create the MKMapView object, which will be added as a subview of viewTouch
    mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    [viewTouch addSubview:mapView];

    //And we display everything!
    [window addSubview:viewTouch];
    [window makeKeyAndVisible];


}


- (void)dealloc {
    [window release];
    [super dealloc];
}


@end

UIViewTouch.h

#import <UIKit/UIKit.h>
@class UIView;

@interface UIViewTouch : UIView {
    UIView *viewTouched;
}
@property (nonatomic, retain) UIView * viewTouched;

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

@end

UIViewTouch.m

#import "UIViewTouch.h"
#import <MapKit/MapKit.h>

@implementation UIViewTouch
@synthesize viewTouched;

//The basic idea here is to intercept the view which is sent back as the firstresponder in hitTest.
//We keep it preciously in the property viewTouched and we return our view as the firstresponder.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    NSLog(@"Hit Test");
    viewTouched = [super hitTest:point withEvent:event];
    return self;
}

//Then, when an event is fired, we log this one and then send it back to the viewTouched we kept, and voilà!!! :)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch Began");
    [viewTouched touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch Moved");
    [viewTouched touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch Ended");
    [viewTouched touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch Cancelled");
}

@end

¡Espero que eso ayude a algunos de ustedes!

Salud

Martín
fuente
14
Agradable. Pequeña sugerencia: debe evitar nombrar sus propias clases con un prefijo de interfaz de usuario. Apple se reserva / desalienta el uso de NS o UI como prefijo de clase, porque estos podrían terminar chocando con una clase de Apple (incluso si es una clase privada).
Daniel Dickison
Hola Daniel, tienes toda la razón, ¡yo también pensé eso! Para completar mi respuesta anterior, permítanme agregar una pequeña advertencia: Mi ejemplo asume que solo hay un objeto viewTouched, que consume todos los eventos. Pero eso no es cierto. Podría tener algunas anotaciones en la parte superior de su mapa y luego mi código ya no funciona. Para trabajar al 100%, debe recordar para cada hitTest la vista asociada a ese evento específico (y eventualmente liberarla cuando se activa touchesEnded o touchesCancelled para que no necesite hacer un seguimiento de los eventos terminados ...).
Martin
1
Código muy útil, ¡gracias Martin! Me preguntaba si intentaste hacer zoom en el mapa después de implementar esto. Para mí, cuando lo hice funcionar usando básicamente el mismo código que tienes arriba, todo parecía funcionar, excepto pellizcar y hacer zoom en el mapa. ¿Alguien tiene alguna idea?
Adam Alexander
¡Hola Adam, yo también tengo esta limitación y realmente no entiendo por qué! Eso es realmente molesto. Si encuentra una solución, ¡hágamelo saber! Thx
Martin
Ok, voté este porque inicialmente pareció resolver mi problema. SIN EMBARGO...! Parece que no puedo conseguir que la función multitáctil funcione. Es decir, aunque paso directamente toquesBegan y toquesMoved to viewTouched (hago mi interceptación en toquesEnded), no puedo hacer zoom en el mapa con gestos de pellizcar. (Continuación ...)
Olie
24
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleGesture:)];   
tgr.numberOfTapsRequired = 2;
tgr.numberOfTouchesRequired = 1;
[mapView addGestureRecognizer:tgr];
[tgr release];


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

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

    //.............
}
Govind
fuente
3
No estoy seguro de por qué esta no es la respuesta principal. Parece funcionar perfectamente y es mucho más sencillo.
elsurudo
12

¡Para un MKMapView, la verdadera solución de trabajo es el reconocimiento de gestos!

Yo Quería dejar de actualizar el centro del mapa en mi ubicación cuando arrastro el mapa o pellizco para hacer zoom.

Entonces, crea y agrega tu reconocedor de gestos al mapView:

- (void)viewDidLoad {

    ...

    // Add gesture recognizer for map hoding
    UILongPressGestureRecognizer *longPressGesture = [[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressAndPinchGesture:)] autorelease];
    longPressGesture.delegate = self;
    longPressGesture.minimumPressDuration = 0;  // In order to detect the map touching directly (Default was 0.5)
    [self.mapView addGestureRecognizer:longPressGesture];

    // Add gesture recognizer for map pinching
    UIPinchGestureRecognizer *pinchGesture = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressAndPinchGesture:)] autorelease];
    pinchGesture.delegate = self;
    [self.mapView addGestureRecognizer:pinchGesture];

    // Add gesture recognizer for map dragging
    UIPanGestureRecognizer *panGesture = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)] autorelease];
    panGesture.delegate = self;
    panGesture.maximumNumberOfTouches = 1;  // In order to discard dragging when pinching
    [self.mapView addGestureRecognizer:panGesture];
}

Consulte la referencia de clase de UIGestureRecognizer para ver todos los reconocedores de gestos disponibles.

Debido a que hemos definido el delegado a sí mismo, tenemos que implementar el protocolo UIGestureRecognizerDelegate:

typedef enum {
    MapModeStateFree,                    // Map is free
    MapModeStateGeolocalised,            // Map centred on our location
    MapModeStateGeolocalisedWithHeading  // Map centred on our location and oriented with the compass
} MapModeState;

@interface MapViewController : UIViewController <CLLocationManagerDelegate, UIGestureRecognizerDelegate> {
    MapModeState mapMode;
}

@property (nonatomic, retain) IBOutlet MKMapView *mapView;
...

Y anule el método gestoRecognizer: gestoRecognizer shouldRecognizeSimuallyWithGestureRecognizer: para permitir reconocer múltiples gestos simultáneamente, si entendí bien:

// Allow to recognize multiple gestures simultaneously (Implementation of the protocole UIGestureRecognizerDelegate)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

Ahora escriba los métodos que serán llamados por nuestros reconocedores de gestos:

// On map holding or pinching pause localise and heading
- (void)handleLongPressAndPinchGesture:(UIGestureRecognizer *)sender {
    // Stop to localise and/or heading
    if (sender.state == UIGestureRecognizerStateBegan && mapMode != MapModeStateFree) {
        [locationManager stopUpdatingLocation];
        if (mapMode == MapModeStateGeolocalisedWithHeading) [locationManager stopUpdatingHeading];
    }
    // Restart to localise and/or heading
    if (sender.state == UIGestureRecognizerStateEnded && mapMode != MapModeStateFree) {
        [locationManager startUpdatingLocation];
        if (mapMode == MapModeStateGeolocalisedWithHeading) [locationManager startUpdatingHeading];
    }
}

// On dragging gesture put map in free mode
- (void)handlePanGesture:(UIGestureRecognizer *)sender {
    if (sender.state == UIGestureRecognizerStateBegan && mapMode != MapModeStateFree) [self setMapInFreeModePushedBy:sender];
}
Joan
fuente
¡Esta solución es perfecta! Algunos rápidos aquí: Si desea interceptar cuando el usuario termina de realizar alguna acción, debería ser suficiente - (void) handleLongPressAndPinchGesture: (UIGestureRecognizer *) sender {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (@ "handleLongPressAndPinchGesture Ended") ; }}
Alejandro Luengo
Además no olvide agregar el delegado <UIGestureRecognizerDelegate>
Alejandro Luengo
6

En caso de que alguien esté intentando hacer lo mismo que yo: quería crear una anotación en el punto donde el usuario toca. Para eso usé la UITapGestureRecognizersolución:

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapOnMap:)];
[self.mapView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer setDelegate:self];

- (void)didTapOnMap:(UITapGestureRecognizer *)gestureRecognizer
{
    CGPoint point = [gestureRecognizer locationInView:self.mapView];
    CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
    .......
}

Sin embargo, didTapOnMap:también se llamó cuando hice tapping en la anotación y se crearía una nueva. La solución es implementar UIGestureRecognizerDelegate:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isKindOfClass:[MKAnnotationView class]])
    {
        return NO;
    }
    return YES;
}
jimpic
fuente
¡Esta es una gran solución! Pero no funciona si usa una vista personalizada como MKAnnotation. En este caso, es posible que la subvista de otra anotación active el reconocedor de gestos. Tuve que comprobar de forma recursiva la supervista de touch.view para encontrar un MKAnnotationView potencial
KIDdAe
3

Probablemente necesitará superponer una vista transparente para captar los toques como se hace tan a menudo con los controles basados ​​en UIWebView. La Vista del mapa ya hace un montón de cosas especiales con un toque para permitir que el mapa se mueva, centre, amplíe, etc. para que los mensajes no lleguen a su aplicación.

Otras dos opciones (NO PROBADAS) en las que puedo pensar:

1) Renuncie al primer respondedor a través de IB y configúrelo en "Propietario del archivo" para permitir que el propietario del archivo responda a los toques. Dudo que esto funcione porque MKMapView extiende NSObject, no UIView y, como resultado, es posible que los eventos táctiles aún no se propaguen hasta usted.

2) Si desea capturar cuando el estado del mapa cambia (como en un zoom) simplemente implemente el protocolo MKMapViewDelegate para escuchar eventos particulares. Mi corazonada es que esta es su mejor oportunidad para atrapar alguna interacción fácilmente (salvo implementar la Vista transparente sobre el mapa). No olvide configurar el controlador de vista que aloja MKMapView como delegado del mapa ( map.delegate = self).

Buena suerte.

MystikEspiral
fuente
MKMapView definitivamente subclases UIView.
Daniel Dickison
2

No he experimentado, pero es muy probable que MapKit se base en un clúster de clases y, por lo tanto, crear subclases es difícil e ineficaz.

Sugeriría hacer que la vista MapKit sea una subvista de una vista personalizada, lo que debería permitirle interceptar eventos táctiles antes de que lleguen a ella.

grahamparks
fuente
¡Hola Graham! ¡Gracias por tu ayuda! Si hago una vista súper personalizada como usted sugiere, ¿cómo podría reenviar eventos al MKMapView? ¿Alguna idea?
Martin
2

Entonces, después de medio día de jugar con esto, encontré lo siguiente:

  1. Como todos los demás descubrieron, pellizcar no funciona. Intenté subclasificar MKMapView y el método descrito anteriormente (interceptarlo). Y el resultado es el mismo.
  2. En los videos del iPhone de Stanford, un tipo de Apple dice que muchas de las cosas de UIKit causarán muchos errores si "transfieres" las solicitudes táctiles (también conocidas como los dos métodos descritos anteriormente), y probablemente no conseguirás que funcione.

  3. LA SOLUCIÓN : se describe aquí: Interceptación / Secuestro de eventos táctiles de iPhone para MKMapView . Básicamente, "captas" el evento antes de que lo reciba cualquier respondedor y lo interpretas allí.

thuang513
fuente
2

En Swift 3.0

import UIKit
import MapKit

class CoordinatesPickerViewController: UIViewController {

    @IBOutlet var mapView: MKMapView!
    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(clickOnMap))
        mapView.addGestureRecognizer(tapGestureRecognizer)
    }

    @objc func clickOnMap(_ sender: UITapGestureRecognizer) {

        if sender.state != UIGestureRecognizerState.ended { return }
        let touchLocation = sender.location(in: mapView)
        let locationCoordinate = mapView.convert(touchLocation, toCoordinateFrom: mapView)
        print("Tapped at lat: \(locationCoordinate.latitude) long: \(locationCoordinate.longitude)")

    }

}
Francisco Castro
fuente
0

Haga de MKMapView una subvista de una vista personalizada e implemente

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

en la vista personalizada para devolver self en lugar de la subvista.

Peter N Lewis
fuente
Hola Peter, ¡Gracias por tu respuesta! Pero creo que al hacer eso, es posible que MKMapView no pueda obtener ningún evento táctil, ¿no es así? Estoy buscando una manera de capturar el evento y luego reenviarlo al MKMapView.
Martin
0

Gracias por la pizza y los gritos, me ahorraste mucho tiempo.

multipletouchenabled funcionará esporádicamente.

viewTouch.multipleTouchEnabled = TRUE;

Al final, cambié las vistas cuando necesitaba capturar el toque (un punto en el tiempo diferente al de necesitar pellizcos):

    [mapView removeFromSuperview];
    [viewTouch addSubview:mapView];
    [self.view insertSubview:viewTouch atIndex:0];
BankStrong
fuente
pero no funciona con el zoom en vivo. También parece que siempre se aleja.
Rog
0

Noto que puede rastrear el número y la ubicación de los toques y obtener la ubicación de cada uno en una vista:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch Moved %d", [[event allTouches] count]);

 NSEnumerator *enumerator = [touches objectEnumerator];
 id value;

 while ((value = [enumerator nextObject])) {
  NSLog(@"touch description %f", [value locationInView:mapView].x);
 }
    [viewTouched touchesMoved:touches withEvent:event];
}

¿Alguien más ha intentado usar estos valores para actualizar el nivel de zoom del mapa? Sería cuestión de registrar las posiciones de inicio y luego las posiciones de llegada, calcular la diferencia relativa y actualizar el mapa.

Estoy jugando con el código básico proporcionado por Martin, y parece que funcionará ...

Dan Donaldson
fuente
0

Esto es lo que reuní, que permite pellizcar zoom en el simulador (no lo he probado en un iPhone real), pero creo que estaría bien:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch Began %d", [touches count]);
 reportTrackingPoints = NO;
 startTrackingPoints = YES;
    [viewTouched touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
 if ([[event allTouches] count] == 2) {
  reportTrackingPoints = YES;
  if (startTrackingPoints == YES) {
   BOOL setA = NO;
   NSEnumerator *enumerator = [[event allTouches] objectEnumerator];
   id value;
   while ((value = [enumerator nextObject])) {
    if (! setA) {
     startPointA = [value locationInView:mapView];
     setA = YES;
    } else {
     startPointB = [value locationInView:mapView];
    }
   }
   startTrackingPoints = NO;
  } else {
   BOOL setA = NO;
   NSEnumerator *enumerator = [[event allTouches] objectEnumerator];
   id value;
   while ((value = [enumerator nextObject])) {
    if (! setA) {
     endPointA = [value locationInView:mapView];
     setA = YES;
    } else {
     endPointB = [value locationInView:mapView];
    }
   }
  }
 }
 //NSLog(@"Touch Moved %d", [[event allTouches] count]);
    [viewTouched touchesMoved:touches withEvent:event];
}

- (void) updateMapFromTrackingPoints {
 float startLenA = (startPointA.x - startPointB.x);
 float startLenB = (startPointA.y - startPointB.y);
 float len1 = sqrt((startLenA * startLenA) + (startLenB * startLenB));
 float endLenA = (endPointA.x - endPointB.x);
 float endLenB = (endPointA.y - endPointB.y);
 float len2 = sqrt((endLenA * endLenA) + (endLenB * endLenB));
 MKCoordinateRegion region = mapView.region;
 region.span.latitudeDelta = region.span.latitudeDelta * len1/len2;
 region.span.longitudeDelta = region.span.longitudeDelta * len1/len2;
 [mapView setRegion:region animated:YES];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
 if (reportTrackingPoints) {
  [self updateMapFromTrackingPoints];
  reportTrackingPoints = NO;
 }


    [viewTouched touchesEnded:touches withEvent:event];
}

La idea principal es que si el usuario usa dos dedos, usted rastrea los valores. Grabo los puntos de inicio y finalización en los puntos de inicio A y B. Luego, registro los puntos de seguimiento actuales, y cuando termino, en touchchesEnded, puedo llamar a una rutina para calcular las longitudes relativas de la línea entre los puntos con los que comienzo , y la línea entre el punto con el que termino usando calc. La relación entre ellos es la cantidad de zoom: multiplico el intervalo de la región por esa cantidad.

Espero que sea útil para alguien.

Dan Donaldson
fuente
0

Tomé la idea de una vista transparente "superpuesta", de la respuesta de MystikSpiral, y funcionó perfectamente para lo que estaba tratando de lograr; Solución rápida y limpia.

En resumen, tenía un UITableViewCell personalizado (diseñado en IB) con un MKMapView en el lado izquierdo y algunos UILabels en el derecho. Quería hacer la celda personalizada para que pudiera tocarla en cualquier lugar y esto impulsaría un nuevo controlador de vista. Sin embargo, tocar el mapa no pasó toques 'hacia arriba' a UITableViewCell hasta que simplemente agregué una UIView del mismo tamaño que la vista del mapa justo encima (en IB) e hice que su fondo fuera el 'color claro' en el código ( ¿No crees que puedes establecer clearColor en IB ??):

dummyView.backgroundColor = [UIColor clearColor];

Pensé que podría ayudar a alguien más; ciertamente, si desea lograr el mismo comportamiento para una celda de vista de tabla.

petert
fuente
"Sin embargo, tocar el mapa no pasó los toques 'arriba' a la UITableViewCell hasta que simplemente agregué una UIView del mismo tamaño que la vista del mapa justo encima de ella" Esto no es cierto. El mapa está procesando toques porque tiene sus propias interacciones de usuario, como el desplazamiento, etc. Si desea detectar el pensamiento en la celda en lugar de interactuar con el mapa, simplemente configure map.isUserInteractionEnabled = false Luego puede usar didSelectRowAtIndexPath en la tabla ver delegado.
BROK3N S0UL