1

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

Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90
LF00
  • 27,015
  • 29
  • 156
  • 295

3 Answers3

3

You must provide height from your data (by calculation of whatever measures your data has), you can't access the cell in that delegate method.

Shebuka
  • 3,148
  • 1
  • 26
  • 43
3

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.

Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90
  • In my code I don't know wyh this not works for me. If I use `return UITableViewAutomaticDimension` in `tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath)` the labels will overlapped in mess. And it seems the cell height is too small. – LF00 Jan 16 '18 at 09:40
  • 1
    your constraints in cell are not good, you have to constrain the label to the left, right, top, and bottom too.. I guess you haven't constrained the label to the bottom – Milan Nosáľ Jan 16 '18 at 09:41
  • I don't know how to constraint the label to each other, so I just put label there in storyboard without constrain config. I think this may be the reason – LF00 Jan 16 '18 at 09:43
  • @KrisRoofe share the code where you design the cell.. or are you using storyboards to define its design? – Milan Nosáľ Jan 16 '18 at 09:45
  • I want to make the dynamic height further. At first I want to only keep 4 lines for the digest label. So I set `cell.digest.numberOfLines = 4`, and when I select cell, the digest label in the selected cell expand to the full height. If I deselect the cell, the label will shrink to 4 line. How can I make it. Thank you. – LF00 Jan 16 '18 at 10:27
3

To set automatic dimension for row height & estimated row height, ensure following steps to make, auto dimension effective for cell/row height layout. I just tested following steps and code and works fine.

  • Assign and implement tableview dataSource and delegate
  • Assign UITableViewAutomaticDimension to rowHeight & estimatedRowHeight
  • Implement delegate/dataSource methods (i.e. heightForRowAt and return a value UITableViewAutomaticDimension to it)

-

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // Set automatic dimensions for row height
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension
}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

For label instance in UITableviewCell

  • Set number of lines = 0 (& line break mode = truncate tail)
  • Set all constraints (top, bottom, right left) with respect to its superview/ cell container.
  • Optional: Set minimum height for label, if you want minimum vertical area covered by label, even if there is no data.

enter image description here

Note: If you've more than one labels (UIElements) with dynamic length, which should be adjusted according to its content size: Adjust 'Content Hugging and Compression Resistance Priority` for labels which you want to expand/compress with higher priority.

Here in this example I set low hugging and high compression resistance priority, that leads to set more priority/importance for contents of second (yellow) label.

enter image description here

Krunal
  • 77,632
  • 48
  • 245
  • 261