Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView dynamic cell height breaks on transition or rotation

Currently I am messing around with swift and dynamic table cell heights. I developed a simple app for iOS8.1 on xcode6.1: https://github.com/ArtworkAD/DynamicCellTest

So to achieve a cell height that stretches with the cell's content I do the following:

  • in storyboard set label lines to 0
  • set labels font to system
  • set constraints for label in cell
  • add self.tableView.rowHeight = UITableViewAutomaticDimension
  • don't override heightForRowAtIndex method

Minimal code is needed:

class MyTableViewController: UITableViewController {

    var entries:Array<String> = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        //create dummy content
        var i = 0
        while i < 10 {
            entries.append("\(i) Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor")
            entries.append("\(i+1) Lorem ipsum dolor sit amet")
            i = i + 2;
        }

        self.tableView.rowHeight = UITableViewAutomaticDimension

    }

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

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = self.tableView.dequeueReusableCellWithIdentifier("basic_cell", forIndexPath: indexPath) as UITableViewCell

        var label = cell.viewWithTag(13)

        if let unwrappedLabel = label as? UILabel {
            unwrappedLabel.text = self.entries[indexPath.row]
        }

        return cell
    }
}

The left image shows the result of the above code. The cell height grows with the content of the label, all nice. However when you click on the disclosure indicator to the detail view and move back again, you get the right image. Why is this happening??

enter image description here

A bad solution for this problem is to override this methods:

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    self.tableView.reloadData()
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    self.tableView.reloadData()
}

override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    self.tableView.reloadData()
}

This way the above problem is solved, but this solution seems not right? A side effect of it is, that when self.tableView.reloadData() is called the table view port jumps to the first cell which doesn't look nice.

Does anyone has an idea what I am doing wrong? Feel free to clone my repo https://github.com/ArtworkAD/DynamicCellTest and test it out.

like image 392
UpCat Avatar asked Nov 06 '14 07:11

UpCat


2 Answers

Adding this seems that it is able to fix rotation problem.

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    self.tableView.estimatedRowHeight = 36.5
}

However, I have another case that there are 4 labels in the cell, which has the same rotation problem, adding this is not enough and I ended up replacing the self.tableView.estimatedRowHeight = 36.5 with reloading visible cells.

like image 153
gabbler Avatar answered Nov 10 '22 14:11

gabbler


I've just solved exactly that problem by overriding tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) in UITableViewDelegate object.

func tableView(tableView: UITableView, 
               estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) 
               -> CGFloat {
    return 200
}

Changing the exact returned value apparently have no effect. The cells are always properly self-sizing. I've got no idea why providing estimated height causes the autolayout to kick in, but it does. iOS 8.1.2, Xcode 6.1.

like image 34
siejkowski Avatar answered Nov 10 '22 13:11

siejkowski