ios - UITapGestureRecognizer rompe UITableView didSelectRowAtIndexPath
(15)
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.
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í. ^^
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 <UIGestureRecognizerDelegate>
en su archivo .h.
¡Esta línea ![touch.view isKindOfClass:[UITableViewCell class]]
verifica si un tableViewCell fue interceptado y descarta cualquier teclado activo.
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)
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.
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
}
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;
}
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.
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()
}
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.
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.
Rápidamente puedes usar esto dentro
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if CheckTheTime() == true {
// do something
}else{
}
}
func CheckTheTime() -> Bool{
return true
}
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)
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"];
}
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.
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
}