Expand and Collapse tableview cells
I tried to implement lots of the given examples on this and other pages with similar questions, but none worked for me since I had to perform some logic in my custom cell (eg. hide unneeded UILables in CustomCell.swift when the cell is collapsed).
Here is the implementation that worked for me:
Create a dictionary:
private var _expandedCells: [IndexPath:Bool] = [:]
Implement the heightForRowAt method:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return _expandedCells[indexPath] == nil ? 70 : _expandedCells[indexPath]! ? 150 : 70 }
Implement the didSelectRowAt method:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { _expandedCells[indexPath] = _expandedCells[indexPath] == nil ? true : !_expandedCells[indexPath]! tableView.reloadRows(at: [indexPath], with: .fade) }
Adjust your customCell:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let cell = cell as? YourCustomTableViewCell, let isExpanded = _expandedCells[indexPath] else { return } cell.set(expanded: isExpanded) }
All you need is implement UITableView
Delegate this way:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
By default, estimatedHeight
is CGRectZero
, when you set some value for it, it enables autoresizing (the same situation with UICollectionView
), you can do even also so:
tableView?.estimatedRowHeight = CGSizeMake(50.f, 50.f);
Then you need to setup you constraints inside your cell.
Check this post: https://www.hackingwithswift.com/read/32/2/automatically-resizing-uitableviewcells-with-dynamic-type-and-ns
Hope it helps)
If you want the cell to get physically bigger, then where you have your store IndexPath
, in heightForRow:
use:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if selectedIndexPath == indexPath {
return 230 + extraHeight
}
return 230.0
}
Then when you want to expand one in the didSelectRow:
selectedIndexPath = indexPath
tableView.beginUpdates
tableView.endUpdates
Edit
This will make the cells animate themselves getting bigger, you dont need the extra animation blocks in the cell.
Edit 2
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if(selectedIndexPath == indexPath) {
selectedIndexPath = nil
if let cell = tableView.cellForRowAtIndexPath(indexPath) as? MyTicketsTableViewCell {
cell.collapse()
}
if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow:indexPath.row+1, section: indexPath.section) as? MyTicketsTableViewCell {
cell.collapse()
}
} else {
selectedIndexPath = indexPath
if let cell = tableView.cellForRowAtIndexPath(indexPath) as? MyTicketsTableViewCell {
cell.expand()
}
if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow:indexPath.row+1, section: indexPath.section) as? MyTicketsTableViewCell {
cell.expand()
}
}
tableView.beginUpdates()
tableView.endUpdates()
}
In MyTicketsTableViewController
class, inside cellForRowAtIndexPath
datasource method add target for the button.
cell.expandButton.addTarget(self, action: "expandorcollapsed:", forControlEvents: UIControlEvents.TouchUpInside)