Cómo interceptar los toques de eventos en un MKMapView o UIWebView objetos?

No estoy seguro de lo que estoy haciendo mal, pero yo trato de coger toca un MKMapView objeto. Yo subclases por la creación de 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 ser que cuando yo uso esta clase, yo 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?

InformationsquelleAutor Martin | 2009-06-26

14 Kommentare

  1. 146

    La mejor manera que he encontrado para lograr esto es con un Gesto de Reconocimiento. Otras maneras de llegar a implicar una gran cantidad de hackish de programación que imperfectamente duplicados de Apple código, especialmente en el caso de multitouch.

    Aquí es lo que debo hacer: Implementar un gesto de reconocimiento que no se puede prevenir y que no puede evitar que otros gesto de reconocedores. Agregar a la vista del mapa y, a continuación, utilizar la gestureRecognizer del touchesBegan, touchesMoved, etc. a su fantasía.

    Cómo detectar cualquier toque en el interior 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
        }
    }
    • ¿qué es «lockedOnUserLocation» para?
    • que es una variable ajena específicas para mi aplicación. se realiza un seguimiento de si el sistema automáticamente debe centrar el mapa en la ubicación actual
    • Esta es la solución perfecta. Necesito una aclaración: En el método «- (void)touchesBegan:(NSSet *)toca withEvent:(UIEvent *)evento», ¿cuál es el propósito de utilizar el código: if (touchesBeganCallback) touchesBeganCallback(toques, event);
    • +1 «menos intrusiva»
    • Esto funciona muy bien para la mayor parte, pero he encontrado un problema con él. Si el código HTML en su web vista contiene un HTML5 video etiqueta con los controles, el gesto de reconocimiento evitará que el usuario pueda usar los controles. He estado buscando una solución para esto, pero todavía tienen que encontrar uno.
    • Gracias por compartir. Por qué no hay un adecuado método de delegado para el seguimiento de las interacciones del usuario con una vista de mapa es más allá de mí, pero este funciona bien.
    • Gran solución, gracias! Yo necesitaba para despedir a un teclado si el usuario pulsa en mi mapview, y esta manejado a la perfección.
    • Funciona muy bien para un webview aswell.
    • He añadido un delegado y dentro de cada TouchesDid… llamar he añadido este tipo de línea: si ( delegado ) [delegado touchesBegan:toques withEvent:evento]; También, agregar un dealloc y llame a sí mismo.touchesBeganCallback = nil para el manejo de la memoria. Gracias por el código, impresionante los recortes
    • Hace el gesto de reconocimiento de la no necesidad de un delegado?
    • Este ejemplo funciona muy bien para responder a los toques de inmediato, pero hay una manera de tener el mapview responder a algo más parecido a un toque dentro del evento?
    • Completa la clase mediante la adición de un touchedEndedCallback, similar a la que él tiene.
    • Este funciona perfectamente, pero ahora, necesito saber el marco aprovechado en que la devolución de llamada o lo que sea. Muchas gracias.
    • Genial!!! A mí me funciona perfectamente.Sólo tenemos que cambiar esta línea con su propio código: auto.lockedOnUserLocation = NO;
    • Trató de usar este para pasar toque acontecimientos que se fueron sucediendo a una vista que está en la parte superior de un mapa de la vista en la vista de mapa. No hubo suerte. Es posible interceptar el gesto en el SuperView y, a continuación, pasar a lo largo de todas las subvistas y dejar que todas las subvistas hacer algo?
    • tengo una duda. necesito una aplicación como : – (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer { if ([[preventingGestureRecognizer descripción] rangeOfString:@»UIScrollViewPanGestureRecognizer»].ubicación != NSNotFound) NO volver; volver [super canBePreventedByGestureRecognizer:preventingGestureRecognizer]; } estoy recibiendo un error. «No visibles @interfaz para ‘UIGestureRecognizer’ declara el selector ‘canBePreventedByGestureRecognizer:'» cualquier ayuda

  2. 29

    Después de un día de pizzas, garganta, finalmente encontré la solución! Muy bueno!

    Pedro, he usado el truco de arriba y ajustado un poco para, finalmente, tener una solución que funciona perfectamente con el 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

    Tengo la esperanza de que ayudará a algunos de ustedes!

    Saludos

    • De niza. Pequeña sugerencia: Usted debe evitar nombrar a sus propias clases con una interfaz de usuario prefijo. Apple se reserva/desaconseja el uso de NS o de interfaz de usuario como un prefijo de clase, debido a que estos podrían terminar chocando con una Manzana de la clase (incluso si es una clase privada).
    • Hey Daniel, Que son perfectamente correctas, pensé que también! Para completar mi respuesta anterior, me permito añadir un poco de advertencia : Mi Ejemplo, suponga que sólo hay un objeto viewTouched, que están consumiendo todos los eventos. Pero eso no es cierto. Usted podría tener algunas Anotaciones en la parte superior del Mapa y, a continuación, mi código no funciona más. Para trabajar 100%, usted tiene que recordar para cada método hitTest la vista asociada a ese evento específico (y, eventualmente, suéltelo cuando touchesEnded o touchesCancelled se activa de modo que no necesitará seguir la pista de acabado de eventos…).
    • Muy útil código, gracias Martin! Me preguntaba si se trató de pinch-zoom en el mapa después de la aplicación de este? Para mí, cuando yo tengo trabajo utilizando básicamente el mismo código que se tiene por encima de todo parecía funcionar, excepto pizca de zoom del mapa. Alguien tiene alguna idea?
    • Hola Adán, también tengo esta limitación y yo realmente no entiendo por qué! Que es realmente molesto. Si usted encuentra una solución, que me haga saber! Thx
    • Ok, he votado en este caso debido a que inicialmente apareció para resolver mi problema. Sin EMBARGO…! Me parece que no puede obtener multi-touch para el trabajo. Que es, aunque yo directamente paso touchesBegan y touchesMoved a viewTouched (yo hago mi interceptar en touchesEnded), no puedo hacer zoom en el mapa con una pizca de gestos. (Continuación…)
    • (Continuación de la anterior). De hecho, este código: De hecho, este código: – (void)touchesBegan:(NSSet *)toca withEvent:(UIEvent *)evento { NSLog(@»Mapa táctil-comenzó a contar: %d», [toques de cuenta]); [viewTouched touchesBegan:toques withEvent:evento]; } – (void)touchesMoved:(NSSet *)toca withEvent:(UIEvent *)evento { NSLog(@»Toque Movido: %d», [toques de cuenta]); [viewTouched touchesMoved:toques withEvent:evento]; } Rendimientos de este registro de salida en el intento de pinch/zoom: Mapa táctil-comenzó a contar: 1 Toque Movido: 1 Toque Movido: 1 [etc., snip] Ayuda?!
    • (¡Bah! Que salió mal. Esperemos que alguien con editar los privilegios de arreglar eso.)
    • Wow! Muy bien hecho. Siguiente pregunta: ¿se Puede detectar cuando un PIN se toca (y la anotación/llamada aparece a la vista)? No veo la manera de hacerlo todavía. 🙁
    • Debo ser la creación de un delegado que se establece en UIViewTouch a ser llamado en uno de los toques método? Por ejemplo, yo soy de la incrustación de mi versión de UIViewTouch (a los que llamo MiniMapViewTouch) en una costumbre UITableViewCell. Cuando el UIViewTouch se hace clic, quiero llevar a cabo un método en la celda personalizada. Por lo tanto, debo crear un delegado, establecer y, a continuación, mostrar la UIViewTouch correcta?
    • Terminé la creación de un delegado de la cadena y ha funcionado bien. Esta respuesta era perfecto. Gracias!
    • Debería liberar el touchView y mapView en delegado de la aplicación del método dealloc.
    • Genial!!! en este trabajo para uiwebview ? me refiero a pellizcar eventos ?

  3. 23
    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];
    
        //.............
    }
    • No estoy seguro de por qué esto no es la respuesta. Parece que funciona perfectamente, y es mucho más sencillo.
  4. 12

    Para un MKMapView la real solución de trabajo es con gesto recognization !

    Me quería dejar de actualizar el centro del mapa en mi lugar cuando me arrastre el mapa o pellizcar para hacer zoom.

    Por lo tanto, crear y añadir su gesto de reconocimiento a la 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];
    }

    Buscar la UIGestureRecognizer De Referencia De La Clase para ver todas las disponibles gesto de reconocimiento.

    Porque hemos definido el delegado de auto, 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 anular la methode gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithgesturerecognizer: con el fin de permitir reconocer los múltiples gestos de forma simultánea, si la he entendido a la derecha :

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

    Escribir ahora los metodos que será llamado por nuestro gesto de reconocedores :

    //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];
    }
    • Esto es excelente – gracias. Multitouch funciona bien.
    • Esta solución es perfecta! Algunos quickies aquí: Si quieres intercep cuando el usuario termina de realizar cualquier acción con esto debería ser suficiente – (void)handleLongPressAndPinchGesture:(UIGestureRecognizer *)sender { if (remitente.estado == UIGestureRecognizerStateEnded) { NSLog(@»handleLongPressAndPinchGesture Terminado»); } }
    • También no se olvide de agregar el delegado <UIGestureRecognizerDelegate>
  5. 5

    Sólo en caso de que alguien está tratando de hacer lo mismo que a mí: yo quería crear una anotación en el punto donde el usuario pulsa. Para que me sirve el UITapGestureRecognizer solució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 fue llamado cuando me tocó en la anotación y un nuevo sería creado. La solución es implementar el UIGestureRecognizerDelegate:

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
    {
        if ([touch.view isKindOfClass:[MKAnnotationView class]])
        {
            return NO;
        }
        return YES;
    }
    • Esta es una gran solución ! Pero no funciona si se utiliza una vista personalizada como MKAnnotation. En este caso, usted puede tener otra anotación de la subvista desencadenar el gesto de reconocimiento. Tuve que comprobar de forma recursiva el superview del tacto.para encontrar un potencial MKAnnotationView
  6. 3

    Usted probablemente necesitará superposición de una visión transparente para coger la toca igual que se hace tan a menudo con UIWebView basado en los controles. La Vista de Mapa ya hace un montón de cosas especiales con un toque en el fin de permitir el mapa para ser movido, centrado, zoom, etc… que los mensajes no están recibiendo direccionado hacia su aplicación.

    Otros dos (no probada) de las opciones que puede pensar:

    1) Renunciar a la primera respuesta, a través de IB y seleccione «Archivo del Propietario» para permitir que el Propietario del archivo para responder a los toques. Yo un dudoso que esto va a funcionar porque MKMapView se extiende NSObject, no UIView ans resultado de los eventos de toque todavía no puede conseguir propagará a usted.

    2) Si desea capturar cuando el Mapa de los cambios de estado (como en un zoom) acaba de implementar el MKMapViewDelegate protocolo para la escucha de los eventos en particular. Mi corazonada es que esta es su mejor tiro en la captura de algunos de interacción con facilidad (corto de implementación de la Visión transparente sobre el Mapa). No olvide configurar el Controlador de Vista de la vivienda de la MKMapView como el mapa del delegado (map.delegate = self).

    Buena Suerte.

    • MKMapView definitivamente subclases de UIView.
  7. 2

    No he experimentado, pero hay una buena probabilidad de MapKit se basa en torno a una clase de clúster, y por lo tanto la creación de subclases es difícil e ineficaz.

    Sugeriría hacer el MapKit ver una subvista de una vista personalizada, que debe permitir a interceptar eventos de toque antes de llegar a ella.

    • Hola Graham! Gracias por su ayuda! Si me hacen una super vista personalizada como usted sugiere, ¿cómo podría entonces reenviar los eventos de la MKMapView? Alguna idea?
  8. 2

    Así que después de la mitad de un día de cachondeo con esto he encontrado el siguiente:

    1. Como todos los demás encontrado, pellizcando no funciona. He intentado tanto, la creación de subclases MKMapView y el método descrito anteriormente (interceptación de ella). Y el resultado es el mismo.
    2. En la universidad de Stanford vídeos para el iPhone, un chico de Apple dice que muchos de los UIKit cosas
      causa un montón de errores si la «transferencia» el toque de las solicitudes (aka los dos métodos descritos anteriormente), y usted probablemente no va a conseguir que funcione.

    3. LA SOLUCIÓN: se describe a continuación: Interceptar/Secuestro iPhone Eventos de Toque para MKMapView. Básicamente, la «captura» en el evento antes de cualquier respondedor consigue, y lo interpretan allí.

  9. 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)")
    
        }
    
    }
  10. 0

    Hacer el MKMapView una subvista de una vista personalizada e implementar

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

    en la vista personalizada para devolver el auto en lugar de la subvista.

    • Hola Pedro, Gracias por tu respuesta! Pero creo que al hacer eso, el MKMapView podría no ser capaz de conseguir cualquier touche eventos, ¿no? Estoy buscando una forma para tomar solo evento y, a continuación, enviarlo a la MKMapView.
  11. 0

    Gracias por la pizza y la garganta – usted me salvó un montón de tiempo.

    multipletouchenabled trabajará de forma esporádica.

    viewTouch.multipleTouchEnabled = TRUE;

    Al final, cambié un vistazo a las opiniones cuando necesitaba para capturar el toque (punto diferente en el tiempo de necesidad pinchzooms):

        [mapView removeFromSuperview];
        [viewTouch addSubview:mapView];
        [self.view insertSubview:viewTouch atIndex:0];
    • pero no funciona con vivo zoom. También parece que siempre alejar el zoom.
  12. 0

    Me doy cuenta de que puede controlar el número y la ubicación de 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];
    }

    Ha nadie trató de usar estos valores para actualizar el mapa del nivel de zoom? Sería un asunto de la grabación de las posiciones de inicio y, a continuación, el acabado de las ubicaciones, el cálculo de la diferencia relativa y actualizar el mapa.

    Estoy jugando con el código básico proporcionado por Martin, y esto parece que se va a trabajar…

  13. 0

    He aquí lo que puse, que no permite una pizca de 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 está utilizando dos dedos, seguimiento de los valores. Puedo grabar los puntos inicial y final en startPoints a y B. Luego debo grabar el seguimiento de los puntos, y cuando he terminado, en touchesEnded, puedo llamar a una rutina para calcular la longitud relativa de la línea entre los puntos que empezar, y la línea entre el punto I final con el uso simple de la hipotenusa calc. La relación entre ellos es la cantidad de zoom: multiplico la región palmo por esa cantidad.

    Espero que sea útil para alguien.

  14. 0

    Tomé la idea de una «superposición» transparente a la vista, de MystikSpiral la respuesta, y funcionó perfectamente para lo que yo estaba tratando de lograr; rápida, limpia y solución.

    En resumen, yo tenía la costumbre UITableViewCell (diseñado en IB) con un MKMapView en el lado izquierdo y algunos UILabels a la derecha. Yo quería hacer el custom celda, por lo que se podía tocar en cualquier lugar y esto generaría un nuevo controlador de vista. Sin embargo tocando el mapa no se toca pasar ‘subir’ a la UITableViewCell hasta que simplemente he añadido un UIView del mismo tamaño de la vista de mapa a la derecha en la parte superior de la misma (IB) y el hecho de que el fondo de la clara de color » en el código (no creo que se pueda establecer clearColor en IB??):

    dummyView.backgroundColor = [UIColor clearColor];

    Pensado que podría ayudar a alguien más; ciertamente, si usted desea conseguir el mismo comportamiento para la vista de la tabla de la célula.

    • «Sin embargo tocando el mapa no se toca pasar ‘subir’ a la UITableViewCell hasta que simplemente he añadido un UIView del mismo tamaño de la vista de mapa a la derecha en la parte superior de la misma» Esto no es cierto. El mapa es el procesamiento de la toques porque tiene su propia interacción con el usuario, tales como el desplazamiento, etc. Si desea detectar, aunque en la celda en lugar de interactuar con el mapa, simplemente mapa del juego.isUserInteractionEnabled = falso entonces puede simplemente utilizar didSelectRowAtIndexPath en la vista de tabla delegado.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea