0

I have a custom cell class with 2 labels displaying a word and its translation. When the user taps one of the labels, I want to open a new view controller with only the label content displayed. We need to understand which label was tapped.

I could not managed to make it work using tapGestureRecognizer and tag on labels because the labels were managed by the class file. I found it easier to add transparent buttons on top of labels.

The segue to the new view controller works fine. But I cannot use anymore the "swipe to delete" on tableViewCells.

When we do the left swipe, the row is moving left, it displays the red squared "DELETE" button on the right side of the row, but at the same time it performs the segue to the new viewController.

How can I hide / deactivate buttons in tableViewCell if left "Swipe to delete" is detected?

I tried to add a left swipeGestureRecognizer and add a common variable isSwipingLeft: Bool to different places (viewDidEndEditing...etc) without success. The best I did was to detect the swipe, hide the button, but could not unhide the button back...

EDIT:

DetailListCell

protocol CustomCellDelegate {
func leftButtonTapped(cell: DetailListCell)
func rightButtonTapped(cell: DetailListCell)
}

class DetailListCell: UITableViewCell {

@IBOutlet weak var entryLeftLbl: UILabel!
@IBOutlet weak var entryRightLbl: UILabel!
@IBOutlet weak var leftButtonOutlet: UIButton!
@IBOutlet weak var rightButtonOutlet: UIButton!
var delegate: CustomCellDelegate?

func configureDetailListCell(entry: Entry) {
entryLeftLbl.isUserInteractionEnabled = true
entryRightLbl.isUserInteractionEnabled = true
// cell configuration to hide/display labels and buttons ...
}

@IBAction func leftButton(_ sender: Any) {
if isSwipingToDelete == false {
delegate?.leftButtonTapped(cell: self)
}}   

@IBAction func rightButton(_ sender: Any) {
if isSwipingToDelete == false {
delegate?.rightButtonTapped(cell: self)
}}}

DetailListVC

override func viewDidLoad() {
detailTableView.delegate = self
detailTableView.dataSource = self        

// Swipe left
let swipeLeft: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(DetailListVC.swipeLeft(gestureRecognizer:)))
swipeLeft.direction = .left
self.view!.addGestureRecognizer(swipeLeft)
}

// Swipe left to detect Swipe to delete
func swipeLeft(gestureRecognizer: UISwipeGestureRecognizer) {
isSwipingToDelete = true
}

func leftButtonTapped(cell: DetailListCell) {
// Find the row of the textField
let indexPath = self.detailTableView.indexPathForRow(at: cell.center)!        
// Find the Entry object of the row/textField selected
if let objs = controller.fetchedObjects , objs.count > 0 {
let item = objs[indexPath.row].faceA
performSegue(withIdentifier: "FullEntryVC", sender: item)
}}

func rightButtonTapped(cell: DetailListCell) {        
// Find the row of the textField
let indexPath = self.detailTableView.indexPathForRow(at: cell.center)!        
// Find the Entry object of the row/textField selected
if let objs = controller.fetchedObjects , objs.count > 0 {
let item = objs[indexPath.row].faceB
performSegue(withIdentifier: "FullEntryVC", sender: item)
}}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "FullEntryVC" {
if let destination = segue.destination as? FullEntryVC {
if let entryFace = sender as? String {
isEditMode = false
destination.entryLabelValue = entryFace
}}}}
Tibo
  • 45
  • 8
  • It seems to me that you are approaching this wrong. Can you give us some pieces of your code? And don't make a transparent button on top of the UILabel. Simply use label.addTarget(...) or check this out http://stackoverflow.com/questions/37630921/how-to-addtarget-to-uilabel-in-swift And make sure user interaction is enabled by using this line of code: yourLabel.isUserInteractionEnabled = true – mcd Apr 19 '17 at 16:21
  • Why don't you use `tableView(_:didSelectRowAt:)` method of `UITableViewDelegate` class to detect what cell was tapped? – Vlad Apr 19 '17 at 17:17
  • @maximilian_cs I updated my 1st post with some code. I already saw the question you linked, but got confused because my labels are referenced in a class file. – Tibo Apr 19 '17 at 20:19
  • @Valdmer : the problem is not to detect the cell, but to detect which label of the cell was tapped. That is why I tried to use `tapGestureRecognizer`. But at a certain point I was blocked because `tableView(_ :didSelectRowAt:)` was fired before `tapGestureRecognizer`. Is there any way to detect what label was tapped from `tableView(_:didSelectRowAt:)`? – Tibo Apr 19 '17 at 20:22
  • @Tibo lets say you have 2 buttons with no segues actions attached to them. On touch up inside one of the buttons you invoke the delegate method to notify ViewController about that action. ViewController performs transition to the next screen. Does that solve your problem? – Vlad Apr 19 '17 at 21:04
  • @Valdmer if we go with the button method that is the piece of code in my post: I am not sure I get how to 'invoke the delegate method to notify ViewController about that action' as you suggest? – Tibo Apr 19 '17 at 21:16
  • @Tibo, Delegate I am referring to is a design patter that you'd implement yourself. There should be plenty examples of it in swift, like [this](https://medium.com/compileswift/implementing-delegates-in-swift-step-by-step-d3211cbac3ef) for example. – Vlad Apr 19 '17 at 21:27
  • @Valdmer Understood. I can use `NSNotification` but I still have the same problem that my method is fired **before** the "swipe to delete" which is in `tableView(_:commitEditingStyle)`. How can I check if there is a "swipe to delete" before using the result of my buttons? – Tibo Apr 20 '17 at 11:42
  • @Tibo, oh I see. Your buttons cover whole cell and even though you're able to swipe cell, once you release it - touch up inside fired. You have 2 options here. 1 - check cell's frame position. 2 - add right navigation bar button which would call `tableView.setEditing(true, animated: true)` – Vlad Apr 20 '17 at 16:17
  • @Tibo actually there's one more option. You can override `willTransition(to state: UITableViewCellStateMask)` method of the `UITableViewCell` – Vlad Apr 20 '17 at 16:34
  • @Tibo `isEditing` property on `UITableViewCell` even better. – Vlad Apr 20 '17 at 19:26
  • @Valdmer You made my day! It is working perfectly now. I added a `if` statement inside the `@IBAction` of my buttons to check if `cell.isEditing == false`. If false then `performSegueWithIdentifier` is run, if true then the "swipe to delete" is working fine. Thanks – Tibo Apr 27 '17 at 11:48
  • Glad to hear that @Tibo! – Vlad Apr 27 '17 at 18:04

1 Answers1

0

As Valdmer proposed I used isEditing property of UITableViewCell. I added a if statement inside the methods of my buttons to check if cell.isEditing == false. If false then performSegue(withIdentifier: ) is run, if true then the "swipe to delete" is working fine and the button does nothing.

I removed all piece of code relative to NSNotification and to swipeLeft(gestureRecognizer: ).

Here is the updated code for one of the button:

func leftButtonTapped(cell: DetailListCell) {
    // Check if "swipe to delete" is detected:
    if cell.isEditing == false {

        // Find the row of the textField
        let indexPath = self.detailTableView.indexPathForRow(at: cell.center)!

        // Find the Entry object of the row/textField selected
        if let objs = controller.fetchedObjects , objs.count > 0 {
            let item = objs[indexPath.row].faceA
            performSegue(withIdentifier: "FullEntryVC", sender: item)
        }
    }
}
Tibo
  • 45
  • 8