recognizer ios iphone objective-c uitapgesturerecognizer touchesbegan

ios - recognizer - ¿Cómo puedo acortar el tiempo que “delayTouchesBegan” retrasa los toquesBegan?



touchesbegan swift 4 (3)

En uno de mis controladores de vista tengo varias vistas que contienen un UITapGestureRecognizer, junto con una implementación de touchesBegan . Necesito priorizar los touchesBegan sobre touchesBegan así que establezco la propiedad delaysTouchesBegan de los reconocedores de gestos en YES . Esto funciona correctamente, pero hay un problema: el reconocedor de gestos retrasa los touchesBegan durante demasiado tiempo. Según la documentation :

Cuando el valor de la propiedad es SÍ, la ventana suspende la entrega de objetos táctiles en la fase UITouchPhaseBegan a la vista. Si el reconocedor de gestos reconoce posteriormente su gesto, estos objetos táctiles se descartan. Sin embargo, si el reconocedor de gestos no reconoce su gesto, la ventana entrega estos objetos a la vista en un toque: Comience: con mensaje de Evento: (y posiblemente un toque de seguimiento Movió: mensaje con Evento: para informarle las ubicaciones actuales de los toques) .

El problema básicamente es que cuando el reconocedor de gestos no reconoce el gesto y entrega estos objetos a touchesBegan , esa operación demora demasiado. ¿Hay alguna forma de acelerarlo, o es solo que el procesamiento del gesto para determinar si es un toque es intensivo y es imposible acortarlo?

Editar:

Aquí hay más información. Este es el código que utilizo para configurar el reconocedor de gestos:

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; tapRecognizer.cancelsTouchesInView = NO; tapRecognizer.delaysTouchesBegan = YES; tapRecognizer.delegate = self; tapRecognizer.numberOfTapsRequired = 1; tapRecognizer.numberOfTouchesRequired = 1; [self.someView addGestureRecognizer:tapRecognizer];


¿Hay alguna forma de acelerarlo, o es solo que el procesamiento del gesto para determinar si es un toque es intensivo y es imposible acortarlo?

El retraso parece depender de cuánto tiempo se tarda en procesar el gesto, así que sí, no es posible ajustarlo (puede registrar -touchesBegan:withEvent: para ver exactamente cuándo se llama). Por ejemplo, si toca un UIView con un UITapGestureRecognizer y no mueve el dedo, el reconocedor de tap aún cree que existe la posibilidad de que levante el dedo en esa misma posición, que se reconocerá como un toque. Por lo tanto, seguirá esperando hasta que haya panorámico o levantado su dedo. Por otro lado, si realiza una panorámica inmediatamente, se envía -touchesBegan:withEvent: casi sin demora.

Las soluciones que puedes probar son:

  1. Utilice la propiedad cancelTouchesInView del reconocedor de cancelTouchesInView lugar. Si lo configura en YES UIView procesará los toques de inmediato y luego, si el reconocedor de gestos termina por reconocer los toques como un gesto, la vista se envía -touchesCancelled:withEvent: donde puede revertir cualquier cambio que haya realizado.

  2. Use cancelTouchesInView con un NSTimer en la vista UIView . Inicie NSTimer en UIView ''s -touchesBegan:withEvent: y cuando se dispare, realice su acción en la vista. Si la vista se envía -touchesCancelled:withEvent: antes de que se -touchesCancelled:withEvent: el temporizador, cancele el temporizador.

  3. Subclase UIGestureRecognizer e implemente su propio reconocedor de tap :)

He creado un ejemplo de las opciones 1 y 2. El ejemplo tiene una vista que puede arrastrar alrededor de la pantalla y la vista tiene un reconocedor de toque que cambia el color de la vista. Si toca la vista pero la arrastra un poco antes de soltarla, verá que el botón "retroceder" ajusta la vista a su posición antes de tocarla. Si configura el JCPanningView de delayResponseToTouch en YES , no verá ningún arrastre dentro del período de retardo.

Esto puede o no puede funcionar para usted dependiendo de cómo sus UIView manejan sus toques.

Aquí está la interfaz del controlador de vista ( JCGestureViewController.h ):

#import <UIKit/UIKit.h> @interface JCGestureViewController : UIViewController @end @interface JCPanningView : UIView @property (nonatomic) BOOL delayResponseToTouch; - (void)changeColor; @end

e implementación ( JCGestureViewController.m ):

#import "JCGestureViewController.h" @interface JCGestureViewController () @property (strong, nonatomic) JCPanningView *panningView; @end @implementation JCGestureViewController - (void)viewDidLoad { [super viewDidLoad]; _panningView = [[JCPanningView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 200.0f)]; [self.view addSubview:_panningView]; UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedPanningView)]; tapRecognizer.cancelsTouchesInView = YES; [_panningView addGestureRecognizer:tapRecognizer]; // set this to YES to have a timer delay the view''s response to touches _panningView.delayResponseToTouch = NO; } - (void)tappedPanningView { [self.panningView changeColor]; } @end @interface JCPanningView () @property (nonatomic) CGPoint touchBeganLocation; @property (nonatomic) CGPoint centerWhenTouchBegan; @property (nonatomic) BOOL respondToTouches; @property (nonatomic) NSTimer *timer; @end @implementation JCPanningView - (void)dealloc { if (_timer) { [_timer invalidate]; _timer = nil; } } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [self randomColor]; } return self; } - (void)changeColor { self.backgroundColor = [self randomColor]; } - (CGFloat)randomRGBValue { return (arc4random() % 255) / 255.0f; } - (UIColor *)randomColor { return [UIColor colorWithRed:[self randomRGBValue] green:[self randomRGBValue] blue:[self randomRGBValue] alpha:1.0f]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesBegan:"); [super touchesBegan:touches withEvent:event]; UITouch *touch = [touches anyObject]; self.touchBeganLocation = [touch locationInView:self.superview]; self.centerWhenTouchBegan = self.center; if (self.delayResponseToTouch) { if (self.timer) { [self.timer invalidate]; } self.timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(startRespondingToTouches) userInfo:nil repeats:NO]; } } - (void)startRespondingToTouches { self.respondToTouches = YES; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { self.center = self.centerWhenTouchBegan; if (self.timer) { [self.timer invalidate]; self.timer = nil; } if (self.delayResponseToTouch) { self.respondToTouches = NO; } } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; if (self.delayResponseToTouch && !self.respondToTouches) { return; } UITouch *touch = [touches anyObject]; CGPoint newLocation = [touch locationInView:self.superview]; CGPoint delta = CGPointMake(newLocation.x - self.touchBeganLocation.x, newLocation.y - self.touchBeganLocation.y); self.center = CGPointMake(self.centerWhenTouchBegan.x + delta.x, self.centerWhenTouchBegan.y + delta.y); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if (self.delayResponseToTouch) { self.respondToTouches = NO; } } @end


Lo solucionaría cambiando UITapGestureRecognizer a UILongPressGestureRecognizer . El título de esos dos es un poco engañoso, pero con UILongPressGestureRecognizer puede establecer la minimumPressDuration :

El período mínimo de los dedos debe presionar en la vista para que se reconozca el gesto.

UILongPressGestureRecognizer *tapRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; tapRecognizer.delegate = self; tapRecognizer.minimumPressDuration = //Up to you; [self.someView addGestureRecognizer:tapRecognizer];


Para esto, cuando se toca la vista en la que tiene que retrasar el toque, puede iniciar un temporizador con el tiempo deseado y, una vez que se complete, puede llamar al método deseado que necesita.