0

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?

fs_tigre
  • 10,650
  • 13
  • 73
  • 146

3 Answers3

1

I'd recommend to:

  1. Create subview, let's call it "resizeableContentView"
  2. Add "resizeableContentView" as a child to cell's "contentView"
  3. Add your views to "resizeableContentView" as a child
  4. Set .clearColor for cell and "contentView" background color if needed
  5. Set width for "resizeableContentView" by action
  6. Don't forget reset cell when it's reused
MakART
  • 31
  • 5
1

you can try this boilerplate code:

cell.buttonAction = { sender in
            UIView.animate(withDuration: 0.5) {
                cell.frame = CGRect(x: 0, y: 0, width: 150, height: 50)
            }
        }
  • @ cagri colak - But how do I get the selected row in method `cellForRowAt indexPath:` ? I need to know what row was tapped. – fs_tigre Jul 10 '19 at 12:44
  • like this: func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { UIView.animate(withDuration: 0.5) { tableView.cellForRow(at: indexPath)?.frame = CGRect(x: 0, y: 0, width: 150, height: 50) } } – CAGRI COLAK Jul 11 '19 at 05:50
  • But I'm not tapping the row directly, I have a button inside the the cell that will be tapped. See, `LorenzOliveto`'s solution. – fs_tigre Jul 11 '19 at 11:03
1

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

LorenzOliveto
  • 7,796
  • 1
  • 20
  • 47
  • I will give this a try and let you know. Quick question thoug, where did `item` come from? Thanks. – fs_tigre Jul 10 '19 at 13:21
  • 1
    It's the same as indexPath.row https://stackoverflow.com/questions/14765730/nsindexpath-item-vs-nsindexpath-row – LorenzOliveto Jul 10 '19 at 14:01
  • It worked, thanks a lot!. FYI - This is how I retrieved the cell... `let currentCell = self.myTableView.cellForRow(at: IndexPath(row:sender.representedIndex!, section: 0))` – fs_tigre Jul 11 '19 at 01:09