Pregunta UIGestureRecognizer bloquea la subvista para manejar eventos táctiles


Estoy intentando descubrir cómo se hace esto la manera correcta. Intenté representar la situación: enter image description here

Estoy agregando un UITableView como una subvista de un UIView. los UIView responde a un toque y pinchGestureRecognizer, pero al hacerlo, la vista de tabla deja de reaccionar a esos dos gestos (aún reacciona a golpes).

Lo he hecho funcionar con el siguiente código, pero obviamente no es una buena solución y estoy seguro de que hay una mejor manera. Esto se pone en el UIView (la supervista):

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if([super hitTest:point withEvent:event] == self) {
        for (id gesture in self.gestureRecognizers) {
            [gesture setEnabled:YES];
        }
        return self;
    }
    for (id gesture in self.gestureRecognizers) {
        [gesture setEnabled:NO];
    }
    return [self.subviews lastObject];
}

74
2018-03-07 17:32


origen


Respuestas:


Tuve un problema muy similar y encontré mi solución en esta pregunta SO. En resumen, configúrate como el delegado para tu UIGestureRecognizer y luego verifique la vista específica antes de permitir que su reconocedor procese el toque. El método delegado relevante es:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch

177
2018-05-04 17:35



El bloqueo de eventos táctiles a subvistas es el comportamiento predeterminado. Usted puede cambiar este comportamiento:

UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];

96
2017-07-20 06:05



Una posibilidad es subclasificar su reconocedor de gestos (si aún no lo ha hecho) y anular -touchesBegan:withEvent: de tal forma que determina si cada toque comenzó en una subvista excluida y llamadas -ignoreTouch:forEvent: para ese toque si lo hizo.

Obviamente, también deberá agregar una propiedad para realizar un seguimiento de la subvista excluida o, mejor aún, una matriz de subvistas excluidas.


4
2018-03-08 15:49



Estaba mostrando una subvista desplegable que tenía su propia tabla. Como resultado, el touch.view A veces devolvería clases como UITableViewCell. Tuve que pasar por la (s) superclase (s) para asegurarme de que era la subclase que pensé que era:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    UIView *view = touch.view;
    while (view.class != UIView.class) {
        // Check if superclass is of type dropdown
        if (view.class == dropDown.class) { // dropDown is an ivar; replace with your own
            NSLog(@"Is of type dropdown; returning NO");
            return NO;
        } else {
            view = view.superview;
        }
    }

    return YES;
}

4
2017-07-24 11:43



Es posible prescindir de cualquier clase.

puedes verificar gestureRecognizers en el selector de devolución de llamada de gestos

si view.gestureRecognizers no contiene su gestureRecognizer, simplemente ignórelo

por ejemplo

- (void)viewDidLoad
{
    UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self     action:@selector(handleSingleTap:)];
    singleTapGesture.numberOfTapsRequired = 1;
}

ver view.gestureRecognizers aquí

- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer
{
    UIEvent *event = [[UIEvent alloc] init];
    CGPoint location = [gestureRecognizer locationInView:self.view];

    //check actually view you hit via hitTest
    UIView *view = [self.view hitTest:location withEvent:event];

    if ([view.gestureRecognizers containsObject:gestureRecognizer]) {
        //your UIView
        //do something
    }
    else {
        //your UITableView or some thing else...
        //ignore
    }
}

2
2018-04-14 05:09



Creé una subclase UIGestureRecognizer diseñada para bloquear todos los reconocedores de gestos adjuntos a una supervista de una vista específica.

Es parte de mi proyecto WEPopover. Puedes encontrarlo aquí.


1
2017-09-18 14:56



Basándose en @Pin Shih Wang responder. Ignoramos todos los grifos que no sean los de la vista que contiene el reconocedor de gestos de toque. Todos los grifos se envían a la jerarquía de vista de la forma habitual que hemos establecido tapGestureRecognizer.cancelsTouchesInView = false. Aquí está el código en Swift3 / 4:

func ensureBackgroundTapDismissesKeyboard() {
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    tapGestureRecognizer.cancelsTouchesInView = false
    self.view.addGestureRecognizer(tapGestureRecognizer)
}

@objc func handleTap(recognizer: UIGestureRecognizer) {
    let location = recognizer.location(in: self.view)
    let hitTestView = self.view.hitTest(location, with: UIEvent())
    if hitTestView?.gestureRecognizers?.contains(recognizer) == .some(true) {
        // I dismiss the keyboard on a tap on the scroll view
        // REPLACE with own logic
        self.view.endEditing(true)
    }
}

1
2017-09-27 12:33



También estaba haciendo un popover y así es como lo hice

func didTap(sender: UITapGestureRecognizer) {

    let tapLocation = sender.locationInView(tableView)

    if let _ = tableView.indexPathForRowAtPoint(tapLocation) {
        sender.cancelsTouchesInView = false
    }
    else {
        delegate?.menuDimissed()
    }
}

0
2017-10-29 20:06



Puedes apagarlo y encenderlo ... en mi código hice algo como esto porque necesitaba apagarlo cuando el teclado no se mostraba, puedes aplicarlo a tu situación:

llamar esto es viewdidload, etc:

NSNotificationCenter    *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(notifyShowKeyboard:) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:@selector(notifyHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];

luego crea los dos métodos:

-(void) notifyShowKeyboard:(NSNotification *)inNotification 
{
    tap.enabled=true;  // turn the gesture on
}

-(void) notifyHideKeyboard:(NSNotification *)inNotification 
{
    tap.enabled=false;  //turn the gesture off so it wont consume the touch event
}

Lo que esto hace es deshabilitar el toque. Sin embargo, tuve que convertir el tap en una variable de instancia y liberarlo en dealloc.


0
2017-12-01 04:12