How to detect tap on clear part of UITableView?
All of the supplied answers, including the accepted answer, add a UITapGestureRecognizer
to the tableView
; while this will work, I've found that this gesture recognizer can interfere with row taps and triggering didSelectRowAtIndexPath
in a somewhat unpredictable/nondeterministic way.
If you want to detect taps in the "blank space" as well as in rows, I highly suggest adding a background view to your table, and add the gesture recognizer there:
let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))self.tableView.backgroundView = UIView()self.tableView.backgroundView?.addGestureRecognizer(tap)
Yes, there are delegate methods, such as:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
However, this will only tell you if a tap occurs on an existing row. If you want to capture taps on the empty space below the rows (or on a section header) you will need to use a gesture recognizer. You can do something like this:
// in viewDidLoad or somewhere similarUITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tableTapped:)];[self.tableView addGestureRecognizer:tap];//.........- (void)tableTapped:(UITapGestureRecognizer *)tap{ CGPoint location = [tap locationInView:self.tableView]; NSIndexPath *path = [self.tableView indexPathForRowAtPoint:location]; if(path) { // tap was on existing row, so pass it to the delegate method [self tableView:self.tableView didSelectRowAtIndexPath:path]; } else { // handle tap on empty space below existing rows however you want }}
EDIT: for an alternative approach, consider Connor Neville's approach from his answer on this post and add the gesture recognizer to the table's background.
Thanks to @Stonz2, swift version:
Swift 4
let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))self.tableView.addGestureRecognizer(tap)@objc func tableTapped(tap:UITapGestureRecognizer) { let location = tap.location(in: self.tableView) let path = self.tableView.indexPathForRow(at: location) if let indexPathForRow = path { self.tableView(self.tableView, didSelectRowAt: indexPathForRow) } else { // handle tap on empty space below existing rows however you want }}
Swift 3
let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))self.tableView.addGestureRecognizer(tap)func tableTapped(tap:UITapGestureRecognizer) { let location = tap.location(in: self.tableView) let path = self.tableView.indexPathForRow(at: location) if let indexPathForRow = path { self.tableView(self.tableView, didSelectRowAt: indexPathForRow) } else { // handle tap on empty space below existing rows however you want }}
Swift 2:
let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))self.tableView.addGestureRecognizer(tap)func tableTapped(tap:UITapGestureRecognizer) { let location = tap.locationInView(self.tableView) let path = self.tableView.indexPathForRowAtPoint(location) if let indexPathForRow = path { self.tableView(self.tableView, didSelectRowAtIndexPath: indexPathForRow) } else { // handle tap on empty space below existing rows however you want }}