¿Cómo interceptar eventos táctiles en objetos MKMapView o UIWebView?
No estoy seguro de qué estoy haciendo mal, pero trato de captar toques en un MKMapView
objeto. Lo subclasifiqué 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?
La mejor manera que he encontrado para lograr esto es con un reconocedor de gestos. Otras formas implican mucha programación hacky que duplica imperfectamente el código de Apple, especialmente en el caso de la tecnología multitáctil.
Esto es lo que hago: implementar un reconocedor de gestos que no se puede prevenir y que no puede impedir otros reconocedores de gestos. Agréguelo a la vista del mapa y luego use los toques iniciados, toques movidos, etc. del gesto Recognizer 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];
ComodínGestureRecognizer.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
ComodínGestureRecognizer.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
RÁPIDO 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
}
}
Después de un día de pizzas y 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 funciona 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
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];
//.............
}