2

I have a viewcontroller with a tableview that's with rowHeight property set to UITableViewAutomaticDimension:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    private var items: [String] = []

    @IBOutlet weak var tableView: UITableView!

    // MARK: - UITableViewDataSource, UITableViewDelegate

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
        cell.expandButton.setTitle(self.items[indexPath.row], for: .normal)
        return cell
    }

    // MARK: - View cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        items = [
            "Allen","Upton","Hu","Yuli","Tiger","Flynn","Lev","Kyle","Sylvester","Mohammad",
            "Harlan","Julian","Sebastian","Porter","Preston","Palmer","Jakeem","Micah","Stephen","Tucker"
        ]

        self.tableView.estimatedRowHeight = 150
        self.tableView.rowHeight = UITableViewAutomaticDimension
    }

}

The interface is defined in IB as follows. It has a custom cell. The cell contains a stackview. In the top part of that stackview, there's a button and in the bottom part, there's a textfield. The textfield is set to hidden initially.

UITableView with prototype cell containing stackview

Tapping the button will unhide the textfield. The cell however, does not expand:

Screenshot of iOS Simulator

Expected is that the cell expands to show the whole stackview. Why doesn't this work?

(I've gotten it to work by reloading the cell but this is an ugly workaround that requires code in the viewcontroller.)

Project on Github: https://github.com/bvankuik/TestResizingCell

Bart van Kuik
  • 4,704
  • 1
  • 33
  • 57

2 Answers2

1

I've "fixed" the problem as follows. In the viewcontroller, I maintain whether a row has its textfield hidden or visible. I removed the button, and just use didSelectRowAt. That reloads the cell:

struct NameCellData {
    var name: String
    var isTextFieldHidden: Bool
}

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    private var items: [NameCellData] = []

    @IBOutlet weak var tableView: UITableView!

    // MARK: - UITableViewDataSource, UITableViewDelegate

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
        cell.nameLabel.text = self.items[indexPath.row].name
        cell.nameCorrectionTextField.isHidden = self.items[indexPath.row].isTextFieldHidden
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.items[indexPath.row].isTextFieldHidden = !self.items[indexPath.row].isTextFieldHidden
        tableView.reloadRows(at: [indexPath], with: .automatic)
    }

    // MARK: - View cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        let names = [
            "Allen","Upton","Hu","Yuli","Tiger","Flynn","Lev","Kyle","Sylvester","Mohammad",
            "Harlan","Julian","Sebastian","Porter","Preston","Palmer","Jakeem","Micah","Stephen","Tucker"
        ]
        for name in names {
            let nameCellData = NameCellData(name: name, isTextFieldHidden: true)
            items.append(nameCellData)
        }

        self.tableView.estimatedRowHeight = 150
        self.tableView.rowHeight = UITableViewAutomaticDimension
    }

}

For full code, see branch of the original test project on Github: https://github.com/bvankuik/TestResizingCell/tree/withReload

Bart van Kuik
  • 4,704
  • 1
  • 33
  • 57
0

Unfortunately, self sizing cells height does not change automatically when you change constraints within them. When you tableView in generated, the delegate's methods are call: numberOfSections, numberOfRowsInSection, cellForRowAt, etc...

It is the case for tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) as well. Which means that if you don't reload your tableView after changing a constraint in a cell, these delegate's methods are not called and your rows heights are not calculated again by auto layout.

The best suggestion I could have instead of reloading the tableView is to call cell.layoutIfNeeded() right after showing the textfield.

Ocunidee
  • 1,769
  • 18
  • 20