UITapGestureRecognizer rompe UITableView didSelectRowAtIndexPath

He escrito mi propia función para desplazar los campos de texto hacia arriba cuando aparece el teclado. Para descartar el teclado tocando fuera del campo de texto, he creado un UITapGestureRecognizer que se ocupa de renunciar a la primera respuesta en el campo de texto cuando se toca.

Ahora también he creado un autocompletado para el campo de texto que crea una UITableView justo debajo del campo de texto y lo rellena con elementos a medida que el usuario ingresa texto.

Sin embargo, al seleccionar una de las entradas en la tabla didSelectRowAtIndexPath , didSelectRowAtIndexPath no recibe una llamada. En cambio, parece que se está llamando al reconocedor de gestos táctiles y simplemente renuncia al primer respondedor.

Supongo que hay alguna manera de decirle al reconocedor de gestos de toque que siga pasando el mensaje de tap a la UITableView , pero no puedo entender de qué se trata. Cualquier ayuda será muy apreciada.

Ok, finalmente lo encontré después de buscar en los documentos del reconocedor de gestos.

La solución fue implementar UIGestureRecognizerDelegate y agregar lo siguiente:

 //////////////////////////////////////////////////////////// // UIGestureRecognizerDelegate methods #pragma mark UIGestureRecognizerDelegate methods - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([touch.view isDescendantOfView:autocompleteTableView]) { // Don't let selections of auto-complete entries fire the // gesture recognizer return NO; } return YES; } 

Eso lo cuidó. Espero que esto ayude a otros también.

La forma más fácil de resolver este problema es:

 UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)]; [tapRec setCancelsTouchesInView:NO]; 

Esto permite que UIGestureRecognizer reconozca el toque y también pase el toque al siguiente respondedor. Una consecuencia no deseada de este método es si tiene una UITableViewCell en pantalla que empuja a otro controlador de vista. Si el usuario toca la fila para cerrar el teclado, se reconocerán tanto el teclado como la inserción. Dudo que esto sea lo que pretendes, pero este método es adecuado para muchas situaciones.

Además, expandiendo la respuesta de Robert, si tiene un puntero a la tabla en cuestión, entonces puede comparar directamente su clase en lugar de tener que convertirla a una cadena y esperar que Apple no cambie la nomenclatura:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if([touch.view class] == tableview.class){ return //YES/NO } return //YES/NO } 

Recuerde, también debe declarar que UIGestureRecognizer tiene un delegado con este código.

Set cancelsTouchesInView de su reconocedor a falso. De lo contrario, “consume” el toque por sí mismo y no lo transfiere a la vista de tabla. Es por eso que el evento de selección nunca ocurre.

por ejemplo, en swift

 let tapOnScreen: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "CheckTheTime") tapOnScreen.cancelsTouchesInView = false view.addGestureRecognizer(tapOnScreen) 

Y para Swift (basado en la respuesta de @Jason):

 class MyAwesomeClass: UIViewController, UIGestureRecognizerDelegate private var tap: UITapGestureRecognizer! override func viewDidLoad() { super.viewDidLoad() self.tap = UITapGestureRecognizer(target: self, action: "viewTapped:") self.tap.delegate = self self.view.addGestureRecognizer(self.tap) } // UIGestureRecognizerDelegate method func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool { if touch.view?.isDescendantOfView(self.tableView) == true { return false } return true } 

Es posible que tenga una solución mejor para agregar un gesto de toque sobre una vista de tabla, pero permitiendo la selección de celda al mismo tiempo:

 func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool { if gestureRecognizer is UITapGestureRecognizer { let location = touch.locationInView(tableView) return (tableView.indexPathForRowAtPoint(location) == nil) } return true } 

Solo busco una celda en el punto de la pantalla donde el usuario está tocando. Si no se encuentra una ruta de índice, entonces dejo que el gesto reciba el toque, de lo contrario lo cancelo. Para mí, funciona genial.

Una solución similar es implementar gestureRecognizer:shouldReceiveTouch: usar la clase de la vista para determinar qué acción tomar. Este enfoque tiene la ventaja de no enmascarar los grifos en la región que rodea directamente la mesa (las vistas de estas áreas aún descienden de las instancias de UITableView, pero no representan las celdas).

Esto también tiene una ventaja de que funciona con varias tablas en una sola vista (sin agregar código adicional).

Advertencia: existe la suposición de que Apple no cambiará el nombre de clase.

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { return ![NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]; } 

Creo que no hay necesidad de escribir bloques de códigos simplemente establezca cancelsTouchesInView en false para su objeto de gesto, de manera predeterminada es true y solo tiene que establecerlo como false . Si está utilizando el objeto UITapGesture en su código y también usa UIScrollView (tableview, collectionview), configure esta propiedad como false

 let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard)) tap.cancelsTouchesInView = false view.addGestureRecognizer(tap) 

Aunque es tarde y muchas personas consideran que las sugerencias anteriores funcionan bien, no pude hacer funcionar los métodos de Jason o TMilligan.

Tengo un TableView estático con múltiples celdas que contienen textFields que reciben entradas de números usando solo el teclado numérico. Esto fue ideal para mí:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if(![touch.view isKindOfClass:[UITableViewCell class]]){ [self.firstTF resignFirstResponder]; [self.secondTF resignFirstResponder]; [self.thirdTF resignFirstResponder]; [self.fourthTF resignFirstResponder]; NSLog(@"Touches Work "); return NO; } return YES; } 

Asegúrese de haber implementado este en su archivo .h.

¡Esta línea ![touch.view isKindOfClass:[UITableViewCell class]] verifica si un tableViewCell fue interceptado y descarta cualquier teclado activo.

Una solución simple es usar las instancias de UIControl en UITableViewCell para obtener toques. Puede agregar vistas con userInteractionEnables == NO a UIControl para obtener grifos.

Aquí está mi solución, que relaciona el marcador de recepción del reconocedor directamente con la visualización del teclado.

En tu delegado reconocedor de gestos de toque:

 #pragma mark - UIGestureRecognizerDelegate - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([PFXKeyboardStateListener sharedInstance].visible) { return YES; } return NO; } 

Y el PFXKeyboardStateListener.h :

 @interface PFXKeyboardStateListener : NSObject { BOOL _isVisible; } + (PFXKeyboardStateListener *)sharedInstance; @property (nonatomic, readonly, getter=isVisible) BOOL visible; @end 

Y el PFXKeyboardStateListener.m :

 static PFXKeyboardStateListener *sharedInstance; @implementation PFXKeyboardStateListener + (PFXKeyboardStateListener *)sharedInstance { return sharedInstance; } + (void)load { @autoreleasepool { sharedInstance = [[self alloc] init]; } } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (BOOL)isVisible { return _isVisible; } - (void)didShow { _isVisible = YES; } - (void)didHide { _isVisible = NO; } - (id)init { if ((self = [super init])) { NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(didShow) name:UIKeyboardDidShowNotification object:nil]; [center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil]; } return self; } @end 

Es posible que desee actualizar el patrón de singleton del oyente del teclado, todavía no lo he hecho. Espero que esto funcione para todos los demás y que funcione para mí. ^^

Implemente este método para delegado de UIGestureRecognizer:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { UIView *superview = touch.view; do { superview = superview.superview; if ([superview isKindOfClass:[UITableViewCell class]]) return NO; } while (superview && ![superview isKindOfClass:[UITableView class]]); return superview != nil; } 

Rápidamente puedes usar esto dentro

 func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { if CheckTheTime() == true { // do something }else{ } } func CheckTheTime() -> Bool{ return true } 

Mi caso fue diferente, incluyendo uisearchbar y uitableview en self.view. Quería descartar el teclado uisearchbar tocando en la vista.

 var tapGestureRecognizer:UITapGestureRecognizer? override func viewWillAppear(animated: Bool) { tapGestureRecognizer = UITapGestureRecognizer(target: self, action:Selector("handleTap:")) } 

En UISearchBar Delegate Methods:

 func searchBarShouldBeginEditing(searchBar: UISearchBar) -> Bool { view.addGestureRecognizer(tapGestureRecognizer!) return true } func searchBarShouldEndEditing(searchBar: UISearchBar) -> Bool { view.removeGestureRecognizer(tapGestureRecognizer!) return true } 

Cuando el usuario toca self.view:

 func handleTap(recognizer: UITapGestureRecognizer) { sampleSearchBar.endEditing(true) sampleSearchBar.resignFirstResponder() } 

Esta es mi solución basada en las respuestas anteriores … Me ha funcionado …

 //Create tap gesture for menu transparent view UITapGestureRecognizer *rightTableTransparentViewTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(rightTableTransparentViewTapMethod:)]; [rightTableTransparentViewTap setCancelsTouchesInView:NO]; [_rightTableTransparentView addGestureRecognizer:rightTableTransparentViewTap]; - (void)rightTableTransparentViewTapMethod:(UITapGestureRecognizer *)recognizer { //Write your code here } 

PROBLEMA: En mi caso, el problema era que originalmente colocaba un botón en cada celda de collectionView y establecía las restricciones para llenar la celda, de modo que cuando se hacía clic en la celda, se hacía clic en el botón; sin embargo, la función de botones estaba vacía, así que nada era que parece estar sucediendo.

REVISIÓN: lo arreglé quitando el botón de la celda de vista de colección.