Estoy tratando de averiguar cómo se hace esto de la manera correcta . Intenté representar la situación:
Estoy agregando UITableView
como una subvista de un UIView
. El UIView
responde a un toque y pinchGestureRecognizer
, pero al hacerlo, la vista de mesa deja de reaccionar a esos dos gestos (todavía reacciona a los deslizamientos).
Lo hice 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 la 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];
}
fuente
hitTest:withEvent:
opointInside:withEvent:
.return !(touch.view == givenView);
si solo desea excluir una vista determinada oreturn !(touch.view.tag == kTagNumReservedForExcludingViews);
cuando desea que el reconocedor deje de procesar el toque en un montón de subvistas diferentes.- (BOOL)isDescendantOfView:(UIView *)view
. Esto también funciona bien- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
cuando se subclasifica UIGestureRecognizer.El bloqueo de eventos táctiles a subvistas es el comportamiento predeterminado. Puede cambiar este comportamiento:
UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)]; r.cancelsTouchesInView = NO; [agentPicker addGestureRecognizer:r];
fuente
translationInView
método. Por lo tanto, implementar el método UIGestureRecognizerDelegate mencionado anteriormente solo provocaría fallas con error... unrecognized selector sent to blah
. Para comprobarlo, usar algo como:CGRectContainsPoint(subview.bounds, [recognizer locationInView:subview])
.Estaba mostrando una subvista desplegable que tenía su propia vista de tabla. Como resultado, a
touch.view
veces devuelve clases comoUITableViewCell
. 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; }
fuente
Sobre la base de la respuesta de @Pin Shih Wang . Ignoramos todos los toques que no sean los de la vista que contiene el reconocedor de gestos de toque. Todos los toques se reenvían a la jerarquía de vistas con la normalidad que establecimos
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) } }
fuente
UISwipeActionStandardButton
? Probé con.some(UISwipeActionStandardButton)
Una posibilidad es subclasificar su reconocedor de gestos (si aún no lo ha hecho) y anularlo de
-touchesBegan:withEvent:
manera que determine si cada toque comenzó en una subvista excluida y solicita-ignoreTouch:forEvent:
ese toque si lo hizo.Obviamente, también deberá agregar una propiedad para realizar un seguimiento de la subvista excluida, o quizás mejor, una matriz de subvistas excluidas.
fuente
Es posible prescindir de heredar ninguna clase.
puedes comprobar los reconocimiento de gestos en el selector de devolución de llamada de gestos
si view.gestureRecognizers no contiene su gestoRecognizer, 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 } }
fuente
singleTapGesture.cancelsTouchesInView = NO;
agregadoviewDidLoad
arribaCreé 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í .
fuente
implemente un delegado para todos los reconocedores de parentView y coloque el método GestureRecognizer en el delegado que es responsable de la activación simultánea de reconocedores:
func gestureRecognizer(UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool { if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) { return true } else { return false }
}
Puede usar los métodos de falla si desea que los niños se activen pero no los reconocedores de padres:
https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate
fuente
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() } }
fuente
Puede apagarlo y encenderlo ... en mi código hice algo como esto ya que necesitaba apagarlo cuando el teclado no se mostraba, puede aplicarlo a su situación:
llamar a 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 hace es deshabilitar el grifo. Sin embargo, tuve que convertir el tap en una variable de instancia y liberarlo en dealloc.
fuente