I'm trying to expand a tableview cell when tapped. Then, when it is tapped again, I want it to go back to its original state.
If cellA is expanded and cellB is tapped, I want cellA to contract and cellB to expand at the same time. So that only one cell can be in its expanded state in any given moment.
My current code:
class MasterViewController: UITableViewController {
var isCellTapped = false
var currentRow = -1
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRowIndex = indexPath
tableView.beginUpdates()
tableView.endUpdates()
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == selectedRowIndex.row {
if isCellTapped == false {
isCellTapped = true
return 140
} else if isCellTapped == true {
isCellTapped = false
return 70
}
}
return 70
}
Current code works well when:
It fails when:
How can I solve this?
The way I achieve adding spacing between cells is to make numberOfSections = "Your array count" and make each section contains only one row. And then define headerView and its height. This works great.
You need to take in account that you need to update your selected row when another is tapped, see the following code :
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == selectedRowIndex {
return 140
}
return 44
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if selectedRowIndex != indexPath.row {
// paint the last cell tapped to white again
self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: self.selectedRowIndex, inSection: 0))?.backgroundColor = UIColor.whiteColor()
// save the selected index
self.selectedRowIndex = indexPath.row
// paint the selected cell to gray
self.tableView.cellForRowAtIndexPath(indexPath)?.backgroundColor = UIColor.grayColor()
// update the height for all the cells
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
}
EDIT:
To handle that the cell where is selected and is tapped again return to its original state you need to check some conditions like the following:
var thereIsCellTapped = false
var selectedRowIndex = -1
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == selectedRowIndex && thereIsCellTapped {
return 140
}
return 44
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.cellForRowAtIndexPath(indexPath)?.backgroundColor = UIColor.grayColor()
// avoid paint the cell is the index is outside the bounds
if self.selectedRowIndex != -1 {
self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: self.selectedRowIndex, inSection: 0))?.backgroundColor = UIColor.whiteColor()
}
if selectedRowIndex != indexPath.row {
self.thereIsCellTapped = true
self.selectedRowIndex = indexPath.row
}
else {
// there is no cell selected anymore
self.thereIsCellTapped = false
self.selectedRowIndex = -1
}
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
With the above modifications in yourdidSelectRowAtIndexPath
and heightForRowAtIndexPath
functions you can see when a cell is tapped its background color it will be changed to gray when it's height grow and when another cell is tapped the cell is painted to white and the tapped to gray and again and again allowing only tap one cell at time.
I though you can benefit and learn how to do a Accordion Menu in this repo I have created and I plan to update very soon to handle better results, it's handle using a UITableView
just like you want.
Any doubt in the repository you can post it here.
I hope this help you.
A simple approach for expanding only one cell at a time:
Swift 3
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var selectedRowIndex = -1
@IBOutlet weak var tableView: UITableView!
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == selectedRowIndex {
return 90 //Expanded
}
return 40 //Not expanded
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedRowIndex == indexPath.row {
selectedRowIndex = -1
} else {
selectedRowIndex = indexPath.row
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
This code will expand the clicked cell and close previously open cell with animation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With