Search code examples
iosswiftuitableviewautolayoutrow-height

Cannot get cell in tableview by heightForRowAt


I try to set the cell height for dynamic content. In the cell I use two UILabel, but I can't access the cell from tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath). As the tableview shows there is cells from the img, but the print("Cell geted") output nothing when I run the app in simulator. I'm just a beginner of IOS developing, so there maybe some wrong config in my app. I want to know what reasons may lead to this

override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return 100
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = self.tableView.cellForRow(at: indexPath) as? ArticleTableViewCell
    if(cell != nil) {
        print("Cell geted")
    }
    return 120
}

enter image description here

I use xib file to defind the cell

Comtum cell class as below

import UIKit

class ArticleTableViewCell: UITableViewCell {

    @IBOutlet weak var time: UILabel!
    @IBOutlet weak var digest: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        time.layer.borderWidth = 1
        //time.layer.masksToBounds = true
        time.layer.cornerRadius = 10
        time.backgroundColor = UIColor.cyan
    }

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

        // Configure the view for the selected state
    }

}

and the storyboard xib file as below

enter image description here


Solution

  • In heightForRow you are supposed to return UITableViewAutomaticDimension. If you do so, then the tableView automatically uses autolayout when it gets a cell from cellForRowAt.

    In short:

    1. In viewDidLoad setup:

      tableView.estimatedRowHeight = 100
      tableView.rowHeight = UITableViewAutomaticDimension
      
    2. Setup autolayout in the cell so that the cell can determine its own size from its contents.

      To setup cell design in a xib cell using autolayout, read this article. In your case you can do the following:

      First, click on the label to select it. Then click on "Add New Constraints" icon in the bottom right corner, see next image:

      enter image description here

      A small popup shows, there set constants that define how far from the top, left, bottom and right corner of the cell the label should be constrained. Make sure red lines indicating the constraints being activated are in full line (they should turn from dashed to full as soon as you fill in constants). Try setting 8 for each direction first, later you can play around with it.

    enter image description here

    However, make sure that you read [this article][1] and also [this article on autolayout][4].
    
    1. Simply return a cell in cellForRowAt. TableView will use the cell's autolayout to determine its height.

    See this answer for details, or my other answer for an example in code.

    EDIT

    To make the cell expandable based on number of lines, in didSelect set the number of lines of the label to 0, and use the following method to tell the tableView to redraw itself:

    func refreshTableAfterCellExpansion() {
        self.tableView.beginUpdates()
        self.tableView.setNeedsDisplay()
        self.tableView.endUpdates()
    }
    

    Do the same, just reversed, in didDeselect.