1

How can I detect a touch on a UITableView? I tried the solutions in this thread. I have my tableView and a scrollView in the same UIViewController with a constraint, so it is complicated to subclass the tableView.
The touches methods are not called:

class ViewController: UIViewController, UIScrollViewDelegate, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var verticalSpacing: NSLayoutConstraint!
    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var tableView: UITableView!


override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    super.touchesBegan(touches, withEvent: event)
    println("touch began")
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
    super.touchesMoved(touches, withEvent: event)
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
    super.touchesEnded(touches, withEvent: event)
    println("touch ended")
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
    super.touchesCancelled(touches, withEvent: event)
}

I added:

tableView.userInteractionEnabled = true
tableView.canCancelContentTouches = false //or true is the same

but it doesn't change anything. The scrollView is visible at the same time as the tableView, but they are not overlapping.

Community
  • 1
  • 1
Paul
  • 6,108
  • 14
  • 72
  • 128

5 Answers5

10

No subclassing required!

Just add a gesture recognizer and be sure to include a call to cancelsTouchesInView

Here's the Swift version:

override func viewDidLoad() {
    super.viewDidLoad()
    view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "handleTap:"))
}

func handleTap(sender: UITapGestureRecognizer) {
    if sender.state == .Ended {
        // Do your thang here!
    }
    sender.cancelsTouchesInView = false
}

Enjoy!

Biodave
  • 397
  • 4
  • 5
3

There are methods that can be useful when working with UITableView that detect changes to the scrollview. These may be useful for you.

For example,

override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    println("Ended decelerating")
}

override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    println("Ended dragging")
}
George Poulos
  • 539
  • 1
  • 6
  • 17
2

Your problem is, that touchesBegan etc. are also methods from UIView so you need to either subclass the UITableView or use a TapGestureRecognizer to make it work like you need it.

It shouldn't be too complicated to subclass the UITableView because you can just set your UITableView class as the class of your tableView in your Storyboard, like you do with UIViewControllers etc.

Christian
  • 22,585
  • 9
  • 80
  • 106
0

Did you try adjusting delaysContentTouches? It could be that if you pressed long enough your touches would register with the default delay.

Have to ask, is there a reason why you cannot just use didSelectRowAtIndexPath?

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
  • Thanks, I will stay with the willBeginDragging and DidEndDragging which seem to work. I had to check the scroll and cancel it when the user stopped dragging. Thanks for the answer – Paul Mar 08 '15 at 11:22
0

Late to the party, but I needed to detect touch not tap on table so I wound up with this:

fileprivate class TouchSensitiveTableView: UITableView {

    fileprivate var onTouchStart: (() -> ())? = nil
    fileprivate var onTouchEnd: (() -> ())? = nil

    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.onTouchStart?()
    }

    public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.onTouchEnd?()
    }
}

Then use like this

private let tableView = TouchSensitiveTableView()

viewDidLoad() {
    ....
    self.tableView.onTouchStart = {[weak self] in .... }
    self.tableView.onTouchEnd = {[weak self] in .... }

Has a minor interaction with the scrolling of the table, but nothng major.

DrPhill
  • 614
  • 5
  • 16