Long story short, iOS8 has a bug with UITableViewAutomaticDimension
So, you can't just call your tableView.rowHeight = UITableViewAutomaticDimension followed by the estimatedRowHeight because when reloading data someway through, you end up getting very jumpy, weird looking scrolling.
The way to mitigate this is apparently to return what the height of the cell is in func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
Since you can't call cellForRowatIndexPath: in heightForRowAtIndexPath:, I basically copied my cellForRowAtIndexPath into the other method and changed it up for height. I can't seem to get it working though because my UILabel (the one with dynamic height in the cell), conforms to one line and just truncates instead of going on for x lines until all the content is displayed.
Note, postBody is the text that has a dynamic height.
My cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = self.feed.dequeueReusableCellWithIdentifier("post") as UITableViewCell
var userName = cell.viewWithTag(1)! as UILabel
var timestamp = cell.viewWithTag(2)! as UILabel
var postBody = cell.viewWithTag(5)! as UILabel
var post = self.posts[indexPath.row]
userName.text = post.name
timestamp.text = post.timestamp
postBody.text = post.body
return cell
}
my heightForRowAtIndexPath:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
var cell: UITableViewCell = self.feed.dequeueReusableCellWithIdentifier("post") as UITableViewCell
var userName = cell.viewWithTag(1)! as UILabel
var timestamp = cell.viewWithTag(2)! as UILabel
var postBody = cell.viewWithTag(5)! as UILabel
var post = self.posts[indexPath.row]
userName.text = post.name
timestamp.text = post.timestamp
postBody.text = post.body
cell.setNeedsLayout()
cell.layoutIfNeeded()
return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
}
Why doesn't it work? With the UITableViewAutomaticDimension I got it working and conforming to the constraints I put through auto-layout, but can't get it here.
The jumpy scrolling you describe isn't a bug - it happens because your estimated height isn't close enough to your actual height.
Don't dequeue a cell in your heightForRowAtIndexPath method. Basically, you're dequeueing a cell which will never be displayed since you're using it for height calculation.
You have a few options:
Improve your estimated height prediction.
In heightForRowAtIndexPath, you can use auto-layout to calculate your actual height by creating a cell instance that isn't dequeued from the table view. You can do this by:
creating your cells programmatically,
creating your cells in a .xib,
copying of your entire view controller and extract one cell from it programmatically
copying your cell in the storyboard and then extracting it via a property
Related
I'm having a lot of issues getting my custom cells to use the dynamic row height.
Here is the xib of my custom cell.
In viewDidLoad for my table view, I set these values:
self.tableView.estimatedRowHeight = 80.0
self.tableView.rowHeight = UITableViewAutomaticDimension
but it doesn't seem to use the dynamic size when it loads the table.
Below is my cellForRowAtIndexPath function.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
let cell = Bundle.main.loadNibNamed("RedditCell", owner: self, options: nil)?.first as? RedditPostCellTableViewCell
let post = self.model?.getPostAt(index: indexPath.row)
cell?.title.text = post?.title
cell?.author.text = post?.author
cell?.upvotes.text = "\(post?.upvotes ?? -1)"
return cell!
}
I can't figure out why this isn't working. Any help would be appreciated!
Please try to set the height in the heightForRowAt
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
self.tableView.estimatedRowHeight = 80
return UITableViewAutomaticDimension
}
You don't need to pre-calculate the height. The problem is with your constraints in your custom UITableViewCell. Your constraints should be set up the way to force UITableViewCell to expand to show the whole label or any other content. Just setup constraints similar to my short example project: https://www.transfernow.net/216sw6l1bler?lng=en, and cell height will be automatically set, as you expected.
Screenshot:
In addition to setting the constraints so that the height of all of the elements in the cell + padding can be used to calculated the overall cell height, you must set the number of lines of your labels to zeros and set them to word wrap if these must grow based on content as well.
I have a expandable tableView, in which when i expand a section, than there are three cell. On firth Cell there is only name and in second cell. It have a big content. Now I want to auto adjust this label height and width according to content.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tblView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomTableViewCell
let dataArrayTblView = dataArrayForTableView
let titleName = dataArrayTblView.valueForKey("name")
let dueDate = dataArrayTblView.valueForKey("deadlinedate")
let description = dataArrayTblView.valueForKey("description")
cell.titleLabel.text = titleName[indexPath.row] as AnyObject! as! String!
cell.dueDateLabel.text = dueDate[indexPath.row] as? String
cell.descriptionLabel.text = description[indexPath.row] as? String
cell.descriptionLabel.sizeToFit()
cell.textLabel?.backgroundColor = UIColor.clearColor()
cell.selectionStyle = .None
return cell
}
But not getting complete content
Try to set this. It will automatically adjust the height of the row for you. If it is not working, then you have something wrong with your constraints inside your storyboard.
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 40
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
You should use UITableViewAutomaticDimension as row height something like,
// this should be set in viewDidload
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140
for that you must use autolayout and should set proper constraints to your label in cell.
Constraint should be in linear chain, I mean your label's top and bottom both constraint must be set and your label should resize according to content so your cell will resize accordingly!
You can refer Self-sizing Table View Cells by Raywenderlich !
Put below in viewDidLoad and set autolayout as per below screenshots.
tblview.rowHeight = UITableViewAutomaticDimension
tblview.estimatedRowHeight = 44
Screenshot 1
Screenshot 2
Screenshot 3
Screenshot 4
Use heightForRowAtIndexPath method to adjust height of row. Calculate
size of string with boundingRectWithSize this method. example:
Try This:
if let YOUR_STRING:NSString = str as NSString? {
let sizeOfString = ns_str.boundingRectWithSize(
CGSizeMake(self.titleLabel.frame.size.width, CGFloat.infinity),options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: lbl.font], context: nil).size
}
I am trying to figure out how get the correct height for my tableview cell that contains a uitextview so that all the content in the uitextview will be display. The textview is not editable and not scrollable, which means that the string for the uitextview is known. I tried simply returning the height of the tableview cell that is in the storyboard in heightForRowAtIndexPath but that cuts off the content if it is too large. I also tried calculating the height for the textView in heightForRowAtIndexPath but it throws an error at runtime:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let cellInfo = UserCellsArray[indexPath.section]
switch cellInfo {
case .userInfo: return 104
case .ubio:
let cell = tableView.dequeueReusableCellWithIdentifier(cellInfo.description, forIndexPath: indexPath) as! UserProfileTableViewCell //error
let oldHeight = cell.userBio.frame.size.height
cell.userBio.text = self.bio
var bodyframe = cell.userBio.frame
bodyframe.size = cell.userBio.contentSize
let newHeight = cell.userBio.contentSize.height
return tableView.rowHeight - oldHeight + newHeight
}
}
Here is what you need to do:
Need to use auto layout in your cell and set up appropriate constraints for UILabel. Since we want to resize the UILabel to fit the text set to it, we will set the number of lines value to 0. And then set the leading, trailing, bottom and top constraints to the UILabel. Please see screenshots here:
In your Table View controller > viewDidLoad call these two lines:
tableView.estimatedRowHeight = 50.0 //Give an approximation here
tableView.rowHeight = UITableViewAutomaticDimension
and also implement delegate method:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
return UITableViewAutomaticDimension
}
I have a Table View called todoTableView with cells that created by the user.
Each cell has Text View.
I want to change the height of the cell by the content of the Text View.
This is what I tried:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: TableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath:indexPath) as! TableViewCell
cell.bounds.size.height = cell.textView.bounds.size.height
return cell
}
Bound Your textview with cell from all sides using marginal constraints.(Leading, Trailing, Top and Bottom constraints)
Disable textView Scrolling
In viewDidLoad() add the following.
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
This will make your cell size according to your textview content size.
Have a look at result :
You don't need to write heightForRowAtIndexPath.
Irfan's answer didn't work for me.
It works after I go to Size Inspector and check "Automatic" for "Row Height".
You should also implement heightForRowAtIndexPath:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return // Calculate your custom row height here.
}
This is the second project I have had this particular problem on. Earlier today I set up a tableview and prototype cell via the storyboard. I added subviews with tag numbers so i could get them from the cellforrowatindexpath delegate method. The subviews though are not in the right place though when i run the app. I use autosizing for layout and made sure to set the delegates. Has anyone had this problem?
POSSIBLY RELEVANT: Sometimes when i leave the storyboard and come back, the subviews changed their frames so that they are flat (height = 0) or x has changed to like 1,500 randomly. No clue why but this happened on the old project I had the problem with as well. The old project I resolved the issue by resetting the frames of all the subviews in the cellforrowatindexpath method but I don't like that as a legit solution.
EDIT: Here is some code and screenshots.
//MARK: - UITableview delegate
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 93.0
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 7;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("order") as? UITableViewCell
println("cell: \(cell)")
var cancel = cell?.viewWithTag(4) as UIButton
var price = cell?.viewWithTag(3) as UILabel
var date = cell?.viewWithTag(2) as UILabel
var address = cell?.viewWithTag(1) as UILabel
cancel.addTarget(self, action: "cancelOrder:", forControlEvents: UIControlEvents.TouchUpInside)
return cell!
}
I've had this issue recently. It seems to be a bug with autolayout for the content view in custom cells.
All I did was in the awakeFromNib for my custom cells reset the autoresizing mask and everything started working as expected.
- (void) awakeFromNib
{
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}