boring91
boring91

Reputation: 1121

Detecting Tap Events for UILabel inside UITableViewCell using UITapGestureRecognizer

I have a UITableViewDataSource with the following

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: OutletDetails.cellIdentifier) as! OutletDetails
    cell.selectionStyle = .none
    cell.isUserInteractionEnabled = true
    cell.location = "Some location will be here"
    let tap = UITapGestureRecognizer(target: self, action: #selector(locationClicked))
    tap.cancelsTouchesInView = false
    tap.numberOfTapsRequired = 1
    cell.location.addGestureRecognizer(tap)
}

where cell.location is a UILabel object. What I'm trying to do here is to detect tap events on the UILabel. I looked all over the Internet and everyone is suggesting this method, however, this code is not working in my case. The method locationClicked is not being called at all. Can anyone tell me what's wrong with my code?

Edit One more thing, is it a good idea to do it this way memory-wise? I mean if we have a long list, then many UIGestureRecognizer objects will be generated for each cell. This is because the method will be called a lot while scrolling the items.

Upvotes: 0

Views: 1722

Answers (2)

boring91
boring91

Reputation: 1121

Add tap gesture to the object and enable its user interaction. Yes you can take button as well.

//Adding tap gesture
let cellNameTapped = UITapGestureRecognizer(target: self, action:     #selector(nameTapped))
nameLabel.isUserInteractionEnabled = true// UILabel made available for touch interaction 
nameLabel.addGestureRecognizer(cellNameTapped) //gesture added

//Method called on touch of nameLabel
@objc func nameTapped(tapGestureRecognizer: UITapGestureRecognizer){
//print(tapGestureRecognizer.view)
}

Upvotes: 1

toddg
toddg

Reputation: 2916

Since you're dequeuing a cell, you will need to somehow get a reference to the UITapGestureRecognizer and either remove it or reuse it. Otherwise every time you reuse a cell, you will be laying another recognizer onto the one that is already on the cell. If you're subclassing the UITableViewCell you can just add the recognizer as a property.

However, using the code you posted I'm suggesting you use a UIButton and add a tag so you can get a reference to it later. You can set the bounds of the button equal to the bounds of the label. Try something like this:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: OutletDetails.cellIdentifier) as! OutletDetails
    cell.selectionStyle = .none
    cell.isUserInteractionEnabled = true
    cell.location = "Some location will be here"

    // If we don't already have a button on our cell, create one and set the tag
    if cell.viewWithTag(103) as? UIButton == nil {
        let newButton = UIButton(frame: cell.location.bounds)
        newButton.tag = 103
        newButton.addTarget(target: self, action: #selector(locationClicked), for: .touchUpInside)
    }
}

Upvotes: 0

Related Questions