ios tableview displays cell as multiline only ios8 not ios7 - uitableview

I have a tableview that displays as multiple lines, as intended, when running the simulator under ios8. When running under ios7 it limits all the cells to 2 rows. The recommendation I found numerous places online was to use numberOfLines = 0 as seen below but this does nothing. Also tried sizeToFit and lineBreakMode and they have no effect. Any ideas? Creating custom cell seems like overkill but do I need to do that?
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
// Configure the cell...
//cell.textLabel?.lineBreakMode = .ByWordWrapping
//cell.textLabel?.sizeToFit()
cell.textLabel?.numberOfLines = 0;
cell.textLabel?.text = "\(formattedPlateComments[indexPath.row])"
return cell
}

Setting numberOfLines=0 on the Label instance is correct, since this specifies an unlimited number of lines. For iOS 7 compatibility, however, you need to also define heightForRowAtIndexPath, i.e.:
func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
return 20 // you can also programmatically calculate a desired height
}
Using numberOfLines=0 and heightForRowAtIndexPath, I was able to display multiple lines in my tableView in both iOS 8 & 7.

Related

Dynamic row height in UITableView using custom cell from xib

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.

Dynamic height cells with a jerky scrolling

I know this is quite a hot topic answered in several places but no answer yet solved my problem. I'm working on an app with a main tableview with multiple cell types (table can be up to hundreds of cells), each one has a different potential height, depends on its content. I'm trying to rely more on dynamic cell heights, calculated by the system when drawing the cell but my scrolling is badly affected when i'm trying to scroll to the bottom of the table.
I understand the estimated height of a cell should be really close to what it is eventually, but there is no way to do that unless I manually calculate the size of each cell by summing up all of its texts, images, constraints and so on... That pretty much knocks the edge out of using dynamic cell heights, doesn't it?
The best solution i've found online is caching up the real cell heights on "cellWillDisplay", but it only works after all cells are presented at least once.
Thing is, when my app loads, it automatically scrolls to bottom without animation so "cellWillDisplay" isn't called for all cells above.
This is my estimatedHeightForRow snippet:
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let object = self.fetchedResultsController?.object(at: indexPath) as? Object {
if let objectID = object.objectIDPermanentString {
if let savedHeight = self.rowsHeights[objectID] {
return savedHeight
}
}
}
return UITableViewAutomaticDimension
}
This is my cellForRow method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let object = self.fetchedResultsController?.object(at: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: object.id, for: indexPath)
self.configureCell(cell: cell, object: object)
return cell
}

UITableViewCell Custom Indentation Width

My app includes a UITableViewController. The default indentation (while editing) is fine, except when on an iPad in landscape mode, when the indentation is way too wide. I've tried setting the indentationWidth and indentationLevel in cellForRowAtIndexPath but nothing seems to work.
I would like my code to work something like this:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell",
forIndexPath: indexPath)
// do other cell configuration here
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
// set the custom indentation level for the cell here
// Tried:
// cell.indentationWidth = 0.1
// cell.indentationLevel = 0
// both have absolutely no effect
}
}
The horrible indentation on iPad in landscape:
The same cells while not editing:
Thanks in advance for any help.
In viewDidLoad, add the following line:
self.tableView.cellLayoutMarginsFollowReadableWidth=NO;
The default setting is YES and that causes wide margins in landscape on newer iPads.

Swift UITableView didSelectRowAtIndexPath bug

I have a UITableView with the subtitles hidden but set up where when someone selects a cell it shows that cell's subtitle. This works fine except that after tapping any cell to reveal its subtitle if you scroll down you will find that every 12 cells have their subtitle unhidden (as well as the one it was supposed to reveal). Here is the code I'm using in didSelectRowAtIndexPath:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
for cell in tableView.visibleCells() {
cell.detailTextLabel??.hidden = true
}
var cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.detailTextLabel?.hidden = false
}
I'm sure this is related to ".visibleCells()" since every 12 cells is about the height of my visible table on my iPhone 6 Plus. When I run it on a 4s in the simulator it's about every 8 cells. But I'm not sure how else to do it besides 'visibleCells'? But it's strange because it's the whole table - all the way down, every 12 cells is showing its subtitle...
thanks for any help
UITableView reuses its cells. So the cell for row a row you clicked on (unhidden the subtitle) may be used for row another row.
The solution is to define prepareForReuse() method in the UITableViewCell subclass (or make the subclass if you do not have one) and hide the subtitle again there.
Add that dataSource's method to your controller. Should work fine.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) {
var identifier = "cellIdentifier"
var cell = tableView. dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath)
cell.detailTextLabel?.hidden = true
return cell
}

UITableViewAutomaticDimension not working until scroll

When the Table View is first loaded, all of the visible cells are the estimatedRowHeight. As I scroll down, the cells are being automatically sized properly, and when I scroll back up the cells that were initially estimatedRowHeight are being automatically sized properly.
Once the cells are being automatically sized, they don't ever seem to go back to being the estimatedRowHeight.
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil)
self.tableView.estimatedRowHeight = 80.0
self.tableView.rowHeight = UITableViewAutomaticDimension
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
and
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as CustomTableViewCell
// Configure the cell...
let restaurant = restaurants[indexPath.row]
cell.namelabel.text = restaurant.name
cell.locationlabel.text = restaurant.location
cell.typelabel.text = restaurant.type
cell.thumbnailImageView.image = UIImage(named: restaurant.image)
cell.thumbnailImageView.layer.cornerRadius = cell.thumbnailImageView.frame.size.width / 2
cell.thumbnailImageView.clipsToBounds = true
cell.accessoryType = restaurant.isVisited ? .Checkmark : .None
return cell
}
Thoughts on how to have the cells autoresize initially?
UPDATE: As of Xcode 7 beta 6 this is no longer an issue
Just call "reloadSections" after your Table is loaded:
self.tableView.reloadSections(NSIndexSet(indexesInRange: NSMakeRange(0, self.tableView.numberOfSections())), withRowAnimation: .None)
Or in Swift 3:
let range = Range(uncheckedBounds: (lower: 0, upper: self.tableView.numberOfSections))
self.tableView.reloadSections(IndexSet(integersIn: range), with: .none)
I ran into the same issue and found out that the accessory cell.accessoryType messes with this automatic resizing when it is not None, so it seems like a bug in Xcode at the moment.
But as #Blankarsch mentioned, calling reloadSections(..) helps to fix this issue if you need to have an accessory.
I think the answers over here have fewer side effects. Specifically adding cell.layoutIfNeeded() in tableView:cellForRowAtIndexPath:
I'm also doing what #nosov suggests as is good practice, but haven't tested if they need to be done in tandem.
just override estimatedHeightForRowAtIndexPath like this
(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
and check your autoLayout constraints in CustomTableViewCell view.
Just make sure that your labels don't have an explicit content size set at Interface Builder. They must be Automatic like the screenshot below for the Automatic Row height to work properly without the need to reload any sections up front.
If you set your constraints based on the cell itself (instead of cell content view), the table is not able to get the proper size. So, to fix this issue, your constraints must be set to the content view.
However, this is problem when your cells supports both configuration with/without accessory view. In that case, the content view gets resized according to the accessory view, and the result may not the the expected by the user. So, in this case, a solution is setting 2 constraints, one to the cell and a second one with lower priority to the cell content view.
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath;
In the function set the cell with the preferred content, in order for UITableViewAutomaticDimension to work flawlessly.
The problem is caused because the cell content is loaded in some other delegate function, so you can see that cells automatically resize to the required size.
Make sure to init your cell in tableView:cellForRowAt:. I've run into this issue even with Xcode 8 when I was setting cell content in tableView:willDisplay:forRowAt:
For me I only have this problem when using willDisplay cell to set the text of my labels
If I set the text of my labels in cellForRowAt index path, everything is fine
For me what solved it was the combination of #[David Hernandez] answer.
Removed the selection from above, and in Cell's layoutSubviews I set the preferredMaxLayoutWidth as this (change 30 to your desired left right spacing)
-(void) layoutSubviews {
[super layoutSubviews];
self.textDescriptionLabel.preferredMaxLayoutWidth = self.frame.size.width - 30;
}
Xcode 9.3, Swift 4.1
adding
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
in addition to
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
worked for me.

Resources