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


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

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

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

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

15 169

15 ответов:

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

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

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

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

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

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

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

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

    return //YES/NO

}

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

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

например swift

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

и для 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
}

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

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

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

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

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

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

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

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

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

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

у меня есть статический 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]] проверяет, был ли постучал tableViewCell и отклоняет любую активную клавиатуру.

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

вот мое решение, которое связывает распознаватель 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

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

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

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

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

func CheckTheTime() -> Bool{
    return true
}

мой случай был другим, включая uisearchbar и uitableview на себя.вид. Я хотел отклонить клавиатуру 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
}

когда пользователь касается себя.вид:

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

Это мое решение, основанное на ответы выше... Это сработало для меня...

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

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

исправить: Я исправил это, удалив кнопку из ячейки представления коллекции.