iosswiftuitableviewuianimation

Animate selected row on button tap


I currently have a table with a custom cell that contains a button and a label. Everything is working fine, the label displays the product name and the button responds to a button tap.

What I would like to be able to do is animate the width of the row/cell where the button was tapped.

Here is the code I currently have...

Main ViewController:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell", for: indexPath) as! CustomCell

        let data = items[indexPath.row]

        cell.displayProductName.text = data.productName

        cell.buttonAction = { sender in
            print("Button tapped...")
        }

        return cell
    }
}

Custom Cell

class CustomCell: UITableViewCell {
    var buttonAction: ((UIButton) -> Void)?

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

    @IBAction func activeInactive(_ sender: UIButton) {
        self.buttonAction?(sender)
    }
}

Table View

enter image description here

How can I animate the width of the row where the button was tapped?


Solution

  • You could subclass UIButton and add an index property where you can store the represented index for the button:

    import UIKit
    
    class UIButtonWithIndex: UIButton {
    
        var representedIndex: Int?
    
    }
    

    Then you should use this class in the storyboard instead UIButton.

    After that add the button as an outlet in your cell and connect in in Interface Builder.

    class CustomCell: UITableViewCell {
        @IBOutlet weak var button: UIButtonWithIndex!
    
        var buttonAction: ((UIButtonWithIndex) -> Void)?
    
        override func awakeFromNib() {
            super.awakeFromNib()
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
        }
    
        @IBAction func activeInactive(_ sender: UIButtonWithIndex) {
            self.buttonAction?(sender)
        }
    
        // Reset the represented index when reusing the cell
        override func prepareForReuse() {
            //Reset content view width
            button.representedIndex = nil
        }
    }
    

    Then when you dequeue the cell in cellForRowAt indexPath set the representedIndex property. Now in your buttonAction you should have the index of the row in which the button was tapped.

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell", for: indexPath) as! CustomCell
    
        let data = items[indexPath.row]
    
        cell.displayProductName.text = data.productName
    
        cell.button.representedIndex = indexPath.item
        cell.buttonAction = { sender in
            print("Button tapped... \(sender.representedIndex)")
        }
    
        return cell
    }
    

    Once you have the index you can retrieve the cell with cellForRowAtIndexPath