Swift and dynamic UITableView row height - ios

I have some rows in the middle of my table that need to have their height resized based on content. the Detail label can have a very long list of CSV values, my attempt to figure it out is as follows:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if(indexPath.section == 0){
return 176;
}
if(indexPath.section == 1){
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
cell.detailTextLabel!.frame.size = CGSize(width: view.bounds.size.width - 115, height: 10000)
cell.detailTextLabel!.sizeToFit()
cell.detailTextLabel!.frame.origin.x = view.bounds.size.width - cell.detailTextLabel!.frame.size.width - 15
return cell.detailTextLabel!.frame.size.height + 20
}
}
return 44;
}
However I get an EXEC_BAD_ACCESS error on:
if let cell = tableView.cellForRowAtIndexPath(indexPath)
Any ideas as to why I get this error or the right way to fix this problem?

You are trying to grab a cell that does not exist yet. The cells returned by cellForRowAtIndexPath(_ indexPath: NSIndexPath) -> UITableViewCell? are the cells you create and return in tableView(_ tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell. So you are trying to calculate the height for a cell that doesn't exist yet by fetching the cell (which again, does not exist yet). It seems like what you want is to prototype a fake placeholder cell that you can set up to get the height for your real cells. To do that, you can make a single cell as a property on your delegate/datasource class, set that cell up once, then return its height as you trying to do in your height method.

Related

How to narrow UITableView cell height if there is dynamic structure in Swift?

I have a tableView and cells. The Cells are loaded from a xib and they have a label with automatic height. I need to narrow one cell if the user taps on it.
I have tried hiding - doesn't work
I have tried removeFromSuperView()- doesn't work
Is there any alternative?
When setting up your tableViewCell store the height anchor you want to update
var yourLabelHeightAnchor: NSLayoutConstraint?
private func setupLayout() {
yourLabelHeightAnchor = yourLabel.heightAnchor.constraint(equalToConstant: 50)
// Deactivate your height anchor as you want first the content to determine the height
yourLabelHeightAnchor?.isActive = false
}
When the user clicks on a cell, notify the tableView that the cell is going to change, and activate the height anchor of your cell.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourTableViewCellIdentifier") as? YourCell
self.tableView.beginUpdates()
cell?.yourLabelHeightAnchor?.isActive = true
self.tableView.endUpdates()
}
Did you try to do something like this:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var result: CGFloat
if (indexPath.row==0) {
result = 50 }
else {result = 130}
return result
}
This is just an example where height is changed for the first row. I tested on my application and it gave result like this.

Swift TableView Crash: "Missing cell for newly visible row"

Im experiencing a crash when adding new rows to a tableview. In short, the crash log says "Missing cell for newly visible row 3".
Reproduction
1. Add N amount of objects to datasource
2. Manually add the same amount
of cells to tableview
3. Reload and animate using beginUpdates - endUpdates
Known Problem
This crash has already been discussed at question and reported at Apple. Their solution to this problem (not using estimated cell heights) does not work for me as i need 2 different heights for the cells.
My tableview is composed out of 2 different cell classes. Both have their own standard height, configured as such:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row % (straightsetLogs.count + 1) == 0 {
return 44
} else {
return tableView.rowHeight
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// (exerciseSets.count / straightsetLogs.count) = amount of (super)sets
// (straightsetLogs.count + 1) = amount of cells needed for 1 (super)set
return (exerciseSets.count / straightsetLogs.count) * (straightsetLogs.count + 1)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Headercell: 1 headercell for every (super)set
if indexPath.row % (straightsetLogs.count + 1) == 0 {
// Create header cells once for every set
let headerCell = tableView.dequeueReusableCell(withIdentifier: CellID.setHeaderCell, for: indexPath) as! SetHeaderTableViewCell
return configureHeaderCell(headerCell, forIndexPath: indexPath, totalCellsPerSet: straightsetLogs.count + 1)
} else {
// Create picker cells for rest of rows
let pickerCell = tableView.dequeueReusableCell(withIdentifier: CellID.setPickerCell, for: indexPath) as! SetPickerTableViewCell
// Configure according to set and movement
return configurePickerCell(pickerCell, forIndexPath: indexPath, totalCellsPerSet: straightsetLogs.count + 1)
}
}
In storyboard i've configured the tableview itself to have a row height of 260.0 and for the header cell i've checked the custom row height box and set it to 44.0.
Current Status
The code for determining the correct cells for the index paths works and the crash can be solved by removing the height for row at indexPath code. But then i end up with all cells being 260.0 height.
Goal
I need 44.0 height for header cells and 260.0 height for picker cells without experiencing this crash.

Expanding Cell in Swift 3

I'm trying to implement an expanding cell using this
here is my heightForRowAt indexPath
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0 : return 70
case 1 :
let cell = self.tableView(tableView, cellForRowAt: indexPath)
if let datePickerCell = cell as? MyDatePickerCell {
return datePickerCell.datePickerHeight()
}
return 260
case 2 : return 80
default : return 60
}
}
The app gets stuck at
let cell = self.tableView(tableView, cellForRowAt: indexPath)
the UITableView is embeded in a modal UIViewController
why is this happening?
I think what is happening is that your tableView is looking for the heights of your cells before loading them in the first place. So you are trying to retrieve the cell before it is loaded, causing a crash.
To fix this you could create a dummy cell before loading the tableView and using that cell in heightForCell. That's more applicable for calculating variable heights for each cell though. In this case maybe hardcode the start height and then use the cell for heights after that.

Static UITableView, make a single cell with dynamic height in Swift

I have a static UITableView which has 12 rows and for 11 rows I know what the height needs to be.
I have a UILabel which has dynamic text which sits inside the 12 row, how do i go about making just that one cell to have a dynamic height based on the text in the UILabel.
I have tried the below code inside viewDidLoad, but it didn't work. The rows remained the same height. I have also set the lines = 0 for the UILabel
tableView.estimatedRowHeight = 100.0
tableView.rowHeight = UITableViewAutomaticDimension
Have you tried this?
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if (indexPath.row < 11) {
// Everything starts at 0, so this covers 0-10
// Whatever your cell height is
return <#fixedCellHeight#>
} else {
// This is your 12th cell (indexPath.row 11), as we start counting at 0
return UITableViewAutomaticDimension
}
}
Adding to #Adrian answer , if you are using static Cells , changing one cell to dynamic height , and others as they are you can edit it to this .
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 11 {
// This is your 12th cell (indexPath.row 11), as we start counting at 0
return UITableViewAutomaticDimension
} else {
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
}
Try this:
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
You can create 2 cell prototype cells for the table view. You give them 2 different id.
And then in your code you override this fonction
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if indexPath.row < 12 {
cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
} else {
cell = tableView.dequeueReusableCellWithIdentifier("cell12", forIndexPath: indexPath)
}
return cell
}
You Can create the dynamic cell with Text height then you can set the static and dynamic cell both in on table view
Here is link to dynamic cell with text How to change cell height dynamically in UITableView static cell
More elegant might be to just implement as suggested:
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Or in Objective C:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
But rather than the row specific logic, add constraints to your static cell's content in the Storyboard to keep the row heights constant. That way if you move rows or change content you don't need to change any code.

Wrap Text in UITableView Custom Cell When It Reaches End of Screen (Swift)

I have a table that loads data from a database but the problem is if the text being loaded is too long, it goes off the screen. I'm trying to find a way for the text to go onto the next line and have the cell resize automatically to fit this change. Does anyone know how this is done? The cell has three labels but one of them is allowed to be multi-lined.
EDIT:
I got it to work using auto constraints but how can I resize the table cell so that the actual items fit inside the cell and do not go over the cell boundary?
Set label number of "Lines" to ZERO. And set "Line Breaks" to "Word Wrap"
Adding these two methods along with above code fixed the problem with custom font
tamilRow.textLabel?.numberOfLines=0
tamilRow.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
func tableView(tableView: UITableView, heightForRowAtIndexPath
indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
swift 5
let unselectedCellHeight: CGFloat = 130.0
func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if selectedCellIndexPath == indexPath {
//return selectedCellHeight
return UITableView.automaticDimension
}
return unselectedCellHeight
}

Resources