我已经编写了自己的函数,当键盘出现时滚动文本字段。为了通过点击离开文本字段来取消键盘,我创建了一个UITapGestureRecognizer,它负责在点击离开时放弃文本字段上的第一个响应器。

现在我还为文本字段创建了一个自动完成,它在文本字段的下面创建了一个UITableView,并在用户输入文本时用项目填充它。

但是,当选择自动补全表中的一个条目时,不会调用didSelectRowAtIndexPath。相反,它似乎是点击手势识别器被调用,只是辞职第一响应器。

我猜有一些方法告诉点击手势识别器继续将点击消息传递给UITableView,但我不知道它是什么。任何帮助都将不胜感激。


当前回答

将你的识别器的cancelsTouchesInView设置为false。否则,它为自己“消耗”触摸,而不将它传递给表视图。这就是为什么选择事件永远不会发生。

例如在swift中

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

其他回答

我的情况是不同的,包括一个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()
}

我可能有一个更好的解决方案,在表格视图上添加一个点击手势,但同时允许单元格选择:

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

我只是在屏幕上用户点击的地方寻找一个单元格。如果没有找到索引路径,那么我让手势接收触摸,否则我取消它。对我来说效果很好。

我有一个不同的情况,我想要触摸手势函数被调用,只有当用户点击表视图之外。如果用户在表视图内点击,那么触摸手势函数不应该被调用。此外,如果触摸手势函数被调用,它仍然应该将触摸事件传递给被点击的视图,而不是消耗它。

生成的代码是阿卜杜勒拉赫曼·马苏德的答案和尼古拉·尼尔森的答案的组合。

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()
        ...
    }
    ...
}

简单的解决方案是使用UITableViewCell中的UIControl实例来获取触摸。你可以添加任何视图userinteractionenabled == NO到UIControl来获得点击。

解决这个问题最简单的方法是:

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

这让UIGestureRecognizer识别点击,并将触摸传递给下一个响应器。这个方法的一个意想不到的结果是,如果你在屏幕上有一个UITableViewCell来推另一个视图控制器。如果用户轻按该行以取消键盘,则键盘和推送都将被识别。我怀疑这是你的意图,但这种方法适用于许多情况。

同时,扩展Robert的回答,如果你有一个指向表视图的指针,那么你可以直接比较它的类,而不是必须转换为字符串,希望苹果不会改变命名法:

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

    return //YES/NO

}

记住,你还必须声明UIGestureRecognizer来拥有一个包含这段代码的委托。