0
votes

I can't figure this out.

I have big UIView with UITapGestureRecognizer.

On this view I put (smaller) UITableView. And now, if I tap on cell, didSelectRowAt is not called, because UIView tap recognizer detect the tap. (It's method is called.)

How do I solve this, that UITableView don't pass touch through to the view.

I try with setting

table.isUserInteractionEnabled = true

and

table.isExclusiveTouch = true

but it doesn't help

EDIT :

A lot of your answers suggest that I have a tableView below view, which is not the case.

I will paste some of my code (changed a little bit for convenience):

class Panel: UIView {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setTapGesture()
    }

    func setTapGesture() {

        tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(UIControlCenterPanel.tapOnPanel(recogniser:)))
        self.addGestureRecognizer(tapGesture)
    }

    func tapOnPanel(recogniser : UITapGestureRecognizer) {
        print("Tap was made")
    }
 }


  class MyPanel: Panel, UITableViewDelegate {
      let table = MyTable()

      override init(frame: CGRect) {
          super.init(frame: frame)

          table.table.delegate = self
          table.isUserInteractionEnabled = true  // This was added as a test
          table.table.isExclusiveTouch = true    // This was added as a test
          table.translatesAutoresizingMaskIntoConstraints = false
          addSubview(table)
          .... // constraints added below
      }

      func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
          print("cell tapped")
      }
  }

  class MyTable: UIView {

      let table = UITableView()

      override init(frame: CGRect) {
          super.init(frame: frame)

          table.translatesAutoresizingMaskIntoConstraints = false
          addSubview(table)
      }
  }

If I click on the cell now, it print:

Tap was made

If I comment out the gesture recogniser like this :

func setTapGesture() {

       // tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(UIControlCenterPanel.tapOnPanel(recogniser:)))
       // self.addGestureRecognizer(tapGesture)
}

then it is printed :

cell tapped
6
Are you implementing cellForRowAt method of tableview? - instanceof
Can you check your table is on top or bottom of view .. May be view is overlaping to table , self.view.bringSubviewToFront(table); - Mitesh jadav
your table must be below your uiview.. add it on top of uiview you will not face this problem - vivek
I am sure, that table view is on top. I added some of my code to be more clear, how my structure work. - Marko Zadravec

6 Answers

1
votes

You can override your container UIView's hitTest method to only let subviews (if any) receive touch events, but never itself. This allows search to continue to unrelated views below. Just replace your UIView with an instance of this class:

class PassThroughView: UIView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let result = super.hitTest(point, with: event)
        return result == self ? nil : result
    }
}
0
votes

Returning appropriate BOOL values in gestureRecognizer:shouldReceiveTouch: will enable you to propagate touches to desired subviews.
Some sample code to achieve this can be like:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{

    if([touch.view isDescendantOfView:table]){
        return NO; // or YES, as desired
    }
}
  • This function needs to be implemented in the ViewController.m
  • You'll need an instance of table, either as an @propertyor extracted via viewWithTag:
0
votes

let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:")) tap.delegate = self tap.cancelsTouchesInView = false view.addGestureRecognizer(tap)// default view

func handleTap(sender: UITapGestureRecognizer? = nil) { view.endEditing(true) // keyboars hides }

0
votes

Try this code

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if touch.view.isDescendantOf(yourTableView) {
        return false
    }
    return true
}
0
votes

You can refer to the answers stated in the question.

Link: UITapGestureRecognizer breaks UITableView didSelectRowAtIndexPath

Setting delegate to filter valid touches according to the type of touched view is the best solution. Some answers suggest to use cancelsTouchesInView = false to tackle this problem but it actually fire both the UITableView didSelectRowAt and also the UITapGestureRecognizer selector at the same time. Choose the right one for yourself.

0
votes

Try this:

tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(UIControlCenterPanel.tapOnPanel(recogniser:)))
self.addGestureRecognizer(tapGesture)
tapGesture.cancelsTouchesInView = false