Nico
Nico

Reputation: 6359

How to know what a tap has been made on a header section of a UITableView?

I have sometimes a header section (just one as I have only one section). I added a gesture (single tap) like the following:

let singleTap = UIShortTapGestureRecognizer(target: self, action: "singleTap:")
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
tableView.headerViewForSection(0)?.addGestureRecognizer(singleTap)

It works. The problem is that when my tableView has just a few rows, if I tap below the last row (on a blank space), it triggers the gesture as well.

How to avoid it? I was thinking a way might be to check if the location of the tap is within the bounds of the header but I don't know how to do it.

For a normal row it's easy, I just use tableView.indexPathForRowAtPoint(point: CGPoint) but what about for a header?

EDIT:

It seems I need to register my header to get something when I call tableView.headerViewForSection(0) but the problem is that my header is an UIView, not a UITableViewHeaderFooterView or UITableViewCell so I cannot register it (I think...).

It was working so far because I added the gesture on the table view as well.

So as the gesture is added on the whole tableView, when I get the view from the gesture, I get the tableView and not the header.

So what I've done is get the header from the tableView using its tag:

let header = tableView.viewWithTag(Tag.Header.rawValue)

and then check the location of the tap if it is inside the header view:

let location = sender.locationInView(sender.view)
if header!.pointInside(location, withEvent: nil) { ... }

Upvotes: 3

Views: 10867

Answers (4)

CristianMoisei
CristianMoisei

Reputation: 2279

I had the same problem and the solution I came up with was to create different targets on a button inside the viewForHeaderInSection method based on the section. I am using a button but this should work just as well with UITapGestureRecognizer

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        // ...

        if section == 0 {
            cell.button.addTarget(self, action: #selector(firstSectionTapped(_:)), for: .touchUpInside)
        } else if section == 1 {
            cell.button.addTarget(self, action: #selector(secondSectionTapped(_:)), for: .touchUpInside)
        }

        // ...

}

Then in the ViewController:

@objc func goalCategoryTapped(_ sender: UITapGestureRecognizer?) {
    print("Section One Tapped")
}

@objc func ideaCategoryTapped(_ sender: UITapGestureRecognizer?) {
    print("Section Two Tapped")
}

Upvotes: 0

Firo
Firo

Reputation: 15566

An easy way to do this is to just attach the listener when the table notifies you (via UITableViewDelegate) it is about to display a header:

override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    let singleTap = // setup gesture

    // Add gesture to already created header
    view.addGestureRecognizer(singleTap)
}

Then you can just setup the selector function:

func singleTap(gesture: UITapGestureRecognizer) {
    let headerView = gesture.view
    // Do something with header view
}

Upvotes: 5

zisoft
zisoft

Reputation: 23078

A possible better approach is to set the gestureRecognizer on the mainView of the viewController (the tableView) and to detect the tapped view in the gestureRecognizer's gesture action:

{
    let singleTap = UIShortTapGestureRecognizer(target: self, action: "singleTap:")
    singleTap.numberOfTapsRequired = 1
    singleTap.numberOfTouchesRequired = 1
    tableView.addGestureRecognizer(singleTap)  // <--
}
...

@IBAction func singleTap(tapGestureRecognizer: UIShortTapGestureRecognizer) {
    // detect the tapped view
    var loc = tapGestureRecognizer.locationInView(self.tableView)

    if (CGRectContainsPoint(tableView.headerViewForSection(0)?.frame, loc)) {
        // header was tapped
        ...
    }
}

Upvotes: 8

Paul Lafytskyi
Paul Lafytskyi

Reputation: 273

Try to add Tag for your HeaderView.

-(void) selectheader:(UITapGestureRecognizer *)gestureRecognizer{
    UIView *headerView = gestureRecognizer.view;
      if (headerView.tag) {

       }
}

And

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 18)];
    view.tag = section;
 // add your gesture 
    return view;
}

Upvotes: 3

Related Questions