UITapGestureRecognizer прерывает UITableView didSelectRowAtIndexPath - PullRequest
192 голосов
/ 19 ноября 2011

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

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

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

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

Ответы [ 18 ]

249 голосов
/ 20 ноября 2011

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

Решением было реализовать 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;
}

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

212 голосов
/ 12 октября 2012

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

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, чтобы иметь делегата с этим кодом.

63 голосов
/ 22 марта 2016

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

, например, в swift

let tapOnScreen: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "CheckTheTime")
tapOnScreen.cancelsTouchesInView = false
view.addGestureRecognizer(tapOnScreen)
35 голосов
/ 22 октября 2015

А для Свифта (на основании ответа @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
}
18 голосов
/ 28 ноября 2014

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

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

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

16 голосов
/ 15 января 2018

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

let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
14 голосов
/ 13 августа 2012

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

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

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

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return ![NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"];
}
4 голосов
/ 12 ноября 2018

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

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

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()
        ...
    }
    ...
}
2 голосов
/ 27 апреля 2019

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

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

Interfacebuilder

- Код

<#gestureRecognizer#>.cancelsTouchesInView = false
1 голос
/ 10 марта 2015

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

...