Hreno  Hrenovich
Hreno Hrenovich

Reputation: 336

How to calculate tableView row height and pass value to heightForRowAtIndexPath

I've a tableView with custom cells. Each cell has different interface, elements. All they have different sizes. Each cell has different type of elements and their count. All these elements are created dynamically, so I'm creating them, making their frames and adding as subviews.

So the problem that heightForRowAtIndexPath executes before cellForRowAtIndexPath where I'm creating the row and constructing its interface and I don't know how to pass calculated height to heightForRowAtIndexPath

How can I count row height before and pass its value to heightForRowIndexPath for correct drawing of my tableView?

Upvotes: 5

Views: 3747

Answers (3)

madmir
madmir

Reputation: 151

  1. Try to create a subclass of UITableViewCell.
  2. All elements created by you put inside UIView, which is put in a cell.
  3. Create three NSLayoutConstraint, one from UIView.top to top of the cell, the second from UIView.bottom to the bottom of the cell and the third - the height of the UIView.
  4. In the viewDidLoad method of tableViewController set row height as the UITableViewAutomaticDimension

:

override func viewDidLoad() {
   super.viewDidLoad()
   self.tableView.rowHeight = UITableViewAutomaticDimension
}
  1. In a subclass of UITableViewCell create a method that will calculate the height of the cell and change NSLayoutConstraint, which sets the height of the cell. For example:

:

func adjustHeightOfInnerView() {
   let height = 100
   self.myInnerCellViewHeightConstraint.constant = height
   self.contentView.setNeedsUpdateConstraints()
}
  1. In the method cellForRowAtIndexPath call the adjustHeightOfTableview:

:

func tableView (tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
   let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! myTableViewCellSubclass
   cell.adjustHeightOfTableview()
   return cell
}

Upvotes: 0

Surely
Surely

Reputation: 1709

If your cell view is really very complex and every component's height are depending on data source. You can try to create the view in heightForRowIndexPath method and then cache the created view to a dictionary in your view controller and use it directly in cellForRowAtIndexPath. In this way you only need to create the view once when user scrolling the table. If the datasource is not changing very frequently, you can reuse the cached view in heightForRowIndexPath as well.

And if the tableview has a lot of rows, you should return an approximate value for height in estimatedHeightForRowAtIndexPath to speed up the loading process of the view controller. Otherwise during loading tableview, it will try to calculate all row's height which may requires a lot of time.

But I really don't think your cell would be so complex. If only some UITextLabels that depends on datasource for the height, you can simply only calculate the height for the label, then add it to other components' height which is fixed.

Upvotes: 3

skorolkov
skorolkov

Reputation: 229

You really should consider subclassing UITableViewCell and adding your custom logic inside your subclass.

Starting from there, you'll have such options:

  1. Create static method in your cell that will receive all data necessary to draw your cell (e.g heithtForCellWithFirstString:secondString:accessoryImage etc) and calculate height using string size computation methods. Use this method inside heightForRowAtIndexPath.

  2. Use autolayout for laying out subviews of your cell and then set table view's row height property to UITableViewAutomaticDimension. This way you won't need heightForRow delegate method at all. There are plenty of tutorials on this, for example: http://www.raywenderlich.com/87975/dynamic-table-view-cell-height-ios-8-swift

Upvotes: 2

Related Questions