UITapGestureRecognizer中断了UITableView didSelectRowAtIndexPath

Jas*_*son 197 uitableview ios uitapgesturerecognizer

我已经编写了自己的函数来在键盘出现时向上滚动文本字段.为了通过点击文本字段来关闭键盘,我创建了一个UITapGestureRecognizer在点击时关注文本字段上的第一响应者.

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

但是,当选择自动完成表中的一个条目时,didSelectRowAtIndexPath不会被调用.相反,似乎轻敲手势识别器正在被调用并且刚刚辞职第一响应者.

我猜是有一些方法可以告诉轻敲手势识别器继续将点击消息传递到下方UITableView,但我无法弄清楚它是什么.任何帮助将非常感激.

Jas*_*son 251

好吧,经过一些搜索手势识别器文档后终于找到了它.

解决方案是实现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;
}
Run Code Online (Sandbox Code Playgroud)

这照顾了它.希望这对其他人也有帮助.

  • 我更幸运了`return![touch.view isKindOfClass:[UITableViewCell class]];` (5认同)
  • @Durgaprasad要在选择单元格时明确地禁用手势识别器*我在`[touch.view isDescendantOfView:self.tableView]`之前添加了`![touch.view isEqual:self.tableView] &&`以排除`tableView`本身(因为`isDescendantOfView:`如果参数视图是接收者视图本身,也会返回`YES`).希望能帮助其他想要相同结果的人. (5认同)

TMi*_*gan 214

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

UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] 
    initWithTarget:self action:@selector(tap:)];
[tapRec setCancelsTouchesInView:NO];
Run Code Online (Sandbox Code Playgroud)

这样可以UIGestureRecognizer识别敲击并将触摸传递给下一个响应者.这种方法的一个意想不到的后果是,如果你有一个UITableViewCell推动另一个视图控制器的屏幕.如果用户点击该行以关闭键盘,则将识别键盘和推送.我怀疑这是你想要的,但这种方法适用于许多情况.

另外,扩展罗伯特的答案,如果你有一个指向相关的tableview的指针,那么你可以直接比较它的类而不必转换为字符串,并希望Apple不会改变命名法:

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

    return //YES/NO

}
Run Code Online (Sandbox Code Playgroud)

请记住,您还必须声明UIGestureRecognizer具有此代码的委托.

  • 谢谢,setCancelsTouchesInView改变了一切:) (4认同)

Abd*_*oud 64

cancelsTouchesInView识别器设置为false.否则,它会"消耗"触摸本身,并且不会将其传递给表格视图.这就是选择事件永远不会发生的原因.

例如在 swift

let tapOnScreen: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "CheckTheTime")
tapOnScreen.cancelsTouchesInView = false
view.addGestureRecognizer(tapOnScreen)
Run Code Online (Sandbox Code Playgroud)


Nik*_*sen 37

而对于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
}
Run Code Online (Sandbox Code Playgroud)


bon*_*ite 18

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

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

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


小智 16

我觉得没有必要写只是简单的代码组块 cancelsTouchesInViewfalse为你的姿势对象,默认情况下它true,你只需要设置它false.如果您UITapGesture在代码中使用对象并使用UIScrollView(tableview,collectionview),则设置此属性false

let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
Run Code Online (Sandbox Code Playgroud)


Rob*_*man 14

类似的解决方案是gestureRecognizer:shouldReceiveTouch:使用视图的类来实现确定要采取的操作.这种方法的优点是不会在直接围绕表格的区域中屏蔽点击(这些区域的视图仍然来自UITableView实例,但它们不代表单元格).

这也有一个好处,它适用于单个视图上的多个表(无需添加额外的代码).

警告:假设Apple不会更改类名.

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


小智 9

对于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
    }
}
Run Code Online (Sandbox Code Playgroud)

当您单击表视图时,此委托方法返回 false 并且didSelectRowAtIndexPath表视图的方法正常工作。


Ali*_*zan 6

我有一个不同的情况,我希望只有当用户在表格视图之外点击时才调用触摸手势功能。如果用户在 table view 内部点击,则不应调用触摸手势功能。此外,如果触摸手势功能被调用,它仍然应该将触摸事件传递给被点击的视图而不是消费它。

生成的代码是 Abdulrahman Masoud 的答案和 Nikolaj Nielsen 的答案的组合。

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")
    }
}
Run Code Online (Sandbox Code Playgroud)

MyViewController课堂上,有UITableView, 在中的课程,onViewDidLoad()我确保调用addGestureRecognizer()

class MyViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        self.addGestureRecognizer()
        ...
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)


Moj*_*ini 6

只需设置cancels touches in viewfalse了下面的任何手势(table/collection)View

- 界面生成器

界面生成器

- 代码

<#gestureRecognizer#>.cancelsTouchesInView = false
Run Code Online (Sandbox Code Playgroud)


小智 6

斯威夫特 5,2020 年 5 月。

我有一个 textField 和一个 tableView 在我输入文本时变得可见。

初始状态 所以当我点击 tableViewCell 或其他东西时,我想要 2 个不同的事件。

正在显示键盘和 tableView

首先我们添加tapGestureRecognizer。

tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
tap.delegate = self
view.addGestureRecognizer(tap)

@objc func viewTapped() {
        view.endEditing(true)
}
Run Code Online (Sandbox Code Playgroud)

然后我们将以下检查添加到 UIGestureRecognizerDelegate 中:

extension StadtViewController: UIGestureRecognizerDelegate {

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view?.isDescendant(of: self.tableView) == true {
        return false
    } else {
        view.endEditing(true)
        return true
    }
}
Run Code Online (Sandbox Code Playgroud)

}

如果我想先隐藏键盘,tableView 将保持可见并响应我的点击。

在此处输入图片说明