UITapGestureRecognizer разрывает UITableView didSelectRowAtIndexPath

Я написал свою собственную функцию для прокрутки текстовых полей до появления клавиатуры. Чтобы отменить клавиатуру, удалив ее из текстового поля, я создал UITapGestureRecognizer, который заботится об отставке первого ответчика в текстовом поле при нажатии.

Теперь я также создал автозаполнение текстового поля, которое создает UITableView чуть ниже текстового поля и заполняет его элементами, когда пользователь вводит текст.

Однако при выборе одной из записей в автоматически заполненной таблице didSelectRowAtIndexPath не вызывается. Вместо этого кажется, что распознающий знак жестов получает вызов и просто уходит в отставку с первого ответчика.

Я предполагаю, что есть способ сообщить распознавателю жестов касания продолжать передавать ответное сообщение вниз до UITableView, но я не могу понять, что это такое. Любая помощь будет очень оценена.

Ответ 1

Хорошо, наконец нашел его после некоторого поиска через документы распознавания жестов.

Решением было реализовать UIGestureRecognizerDelegate и добавить следующее:

////////////////////////////////////////////////////////////
// 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;
}

Это позаботилось об этом. Надеюсь, это тоже поможет другим.

Ответ 2

Самый простой способ решить эту проблему:

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

Это позволяет UIGestureRecognizer распознать кран и также передать прикосновение к следующему ответчику. Непредвиденным следствием этого метода является наличие на экране UITableViewCell на экране другого контроллера представлений. Если пользователь удаляет строку, чтобы закрыть клавиатуру, будут распознаны клавиатура и нажатие. Я сомневаюсь, что это то, что вы намереваетесь, но этот метод подходит для многих ситуаций.

Кроме того, при расширении ответа Роберта, если у вас есть указатель на рассматриваемый столбец, вы можете напрямую сравнить его класс, а не конвертировать его в строку и надеяться, что Apple не изменит номенклатуру:

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

    return //YES/NO

}

Помните, что вы должны также объявить UIGestureRecognizer делегатом с этим кодом.

Ответ 3

Установите cancelsTouchesInView вашего распознавателя на значение false. В противном случае он "потребляет" прикосновение для себя и не передает его в виде таблицы. Вот почему событие выбора никогда не происходит.

например, в swift

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

Ответ 4

И для Swift (на основе ответа от @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
}

Ответ 5

У меня может быть лучшее решение для добавления жестов кран в представлении таблицы, но одновременного выбора ячейки:

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

Я просто ищу ячейку в точке экрана, где пользователь нажимает. Если индексный путь не найден, я позволяю жестом получать прикосновение, иначе я отменил его. Для меня это отлично работает.

Ответ 6

Я думаю, что нет необходимости писать блоки кодов, достаточно просто установить для cancelsTouchesInView значение false для вашего объекта жеста, по умолчанию это значение true и вам просто нужно установить значение false. Если вы используете объект UITapGesture в своем коде, а также используете UIScrollView (tableview, collectionview), тогда установите для этого свойства значение false

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

Ответ 7

Аналогичное решение заключается в реализации gestureRecognizer:shouldReceiveTouch: с использованием класса представления, чтобы определить, какое действие нужно предпринять. Преимущество такого подхода заключается в том, что он не скрывает краны в области, непосредственно связанной с таблицей (эти виды области все еще спускаются из экземпляров UITableView, но они не представляют ячейки).

У этого также есть бонус, что он работает с несколькими таблицами на одном представлении (без добавления дополнительного кода).

Предостережение: есть предположение, что Apple не изменит имя класса.

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

Ответ 8

У меня была другая ситуация, когда я хотел, чтобы функция жеста касания вызывалась только тогда, когда пользователь нажимал вне таблицы. Если пользователь нажал внутри табличного представления, то не нужно вызывать функцию сенсорного жеста. Кроме того, если вызывается функция жеста касания, она все равно должна передавать событие касания в представление, к которому было применено нажатие, а не потреблять его.

Полученный код представляет собой комбинацию ответа Абдулрахмана Масуда и ответа Николая Нильсена.

extension MyViewController: UIGestureRecognizerDelegate {
    func addGestureRecognizer() {
        let tapOnScreen = UITapGestureRecognizer(target: self,
                                                action: #selector(functionToCallWhenUserTapsOutsideOfTableView))

        // stop the gesture recognizer from "consuming" the touch event, 
        // so that the touch event can reach other buttons on view.
        tapOnScreen.cancelsTouchesInView = false

        tapOnScreen.delegate = self

        self.view.addGestureRecognizer(tapOnScreen)
    }

    // if your tap event is on the menu, don't run the touch event.
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view?.isDescendant(of: self.tableView) == true {
            return false
        }
        return true
    }

    @objc func functionToCallWhenUserTapsOutsideOfTableView() {

        print("user tapped outside table view")
    }
}

И в классе MyViewController классе, который имеет UITableView, в onViewDidLoad() я убедился в том, чтобы вызвать addGestureRecognizer():

class MyViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        self.addGestureRecognizer()
        ...
    }
    ...
}

Ответ 9

Просто установите cancels touches in view на false для любого жеста под представлением (table/collection)View:

Интерфейсный строитель

Interfacebuilder

- Код

<#gestureRecognizer#>.cancelsTouchesInView = false

Ответ 10

Пока он опаздывает, и многие люди считают, что приведенные выше предложения работают нормально, я не мог заставить методы Джейсона или Тмиллигана работать.

У меня есть таблица Static tableView с несколькими ячеями, содержащими текстовые поля, которые получают числовые входы, используя только цифровую клавиатуру. Это было идеально для меня:

- (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;
}

Убедитесь, что вы внедрили этот <UIGestureRecognizerDelegate> в свой .h файл.

Эта строка ![touch.view isKindOfClass:[UITableViewCell class]] проверяет, была ли задействована таблицаViewCell и отклоняется любая активная клавиатура.

Ответ 11

Простое решение использует экземпляры UIControl в UITableViewCell, чтобы получить штрихи. Вы можете добавлять любые представления с помощью userInteractionEnables == NO для UIControl для получения ответвлений.

Ответ 12

Для Swift 4.2 решением было реализовать UIGestureRecognizerDelegate и добавить следующее:

extension ViewController : UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view!.isDescendant(of: tblView) {
            return false
        }
        return true
    }
}

когда вы щелкаете по табличному представлению, этот метод делегата возвращает false, а метод didSelectRowAtIndexPath табличного представления работает правильно.

Ответ 13

Вот мое решение, которое напрямую связывает распознаватель shouldReceiveTouch с тем, отображается ли клавиатура.

В делегате распознавателя распознавания жестов:

#pragma mark - UIGestureRecognizerDelegate

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

    return NO;
}

И PFXKeyboardStateListener.h:

@interface PFXKeyboardStateListener : NSObject
{
    BOOL _isVisible;
}

+ (PFXKeyboardStateListener *)sharedInstance;

@property (nonatomic, readonly, getter=isVisible) BOOL visible;

@end

И 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

Возможно, вам захочется обновить одноэлементный шаблон прослушивателя клавиатуры, я еще не получил его. Надеюсь, это работает для всех остальных, а также для меня. ^^

Ответ 14

Внедрите этот метод для делегата 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;
}

Ответ 15

В быстром вы можете использовать это внутри

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

func CheckTheTime() -> Bool{
    return true
}

Ответ 16

Мое дело было другим, включая uisearchbar и uitableview на self.view. Я хотел убрать клавиатуру uisearchbar, коснувшись вида.

var tapGestureRecognizer:UITapGestureRecognizer?

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

В методах делегатов UISearchBar:

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

Когда пользователь затрагивает self.view:

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

Ответ 17

Это моё решение, основанное на ответах выше... У меня это сработало...

//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
}

Ответ 18

ПРОБЛЕМА: В моем случае проблема заключалась в том, что я изначально помещал кнопку в каждую ячейку collectionView и устанавливал ограничения для заполнения ячейки, чтобы при нажатии на ячейку она нажимала кнопку, однако функция кнопок была пустой, поэтому ничего не было. кажется, что происходит.

ИСПРАВЛЕНИЕ: Я исправил это, удалив кнопку из ячейки представления коллекции.