I am working on a tableView, goal is to implement a expandible/collapsible tableView cells. The number of cells is completely dynamic.
I have things working, but with a small problem. I am using didSelectRowAtIndexPath to toggle expand/collapse cell. So what happens now is the toggle executes by tapping anywhere on the cell. :-(
Inside the cell, I have two UIViews (Header and Detail precisely). I need the toggle expand/collapse to work only when I tap on Header and not the whole cell.
For that, I am fetching the indexPath like here but that doesn't work since indexPathsForSelectedRows returns nil.
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myVouchers.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if selectedIndex == indexPath.row {
return 150.0
}
else {
return 40.0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
cell = tableView.dequeueReusableCellWithIdentifier("CollapsedCell", forIndexPath: indexPath) as! CollapsedCell
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action:#selector(VoucherDetailViewController.expandCell(_:)))
(cell as! CollapsedCell).headerView.addGestureRecognizer(tapGestureRecognizer)
return cell
}
func getIndexPathForSelectedCell() -> NSIndexPath? {
var indexPath: NSIndexPath?
if tableView.indexPathsForSelectedRows?.count > 0 { //**nil is returned here**
indexPath = (tableView.indexPathsForSelectedRows?[0])! as NSIndexPath
}
return indexPath
}
func expandCell(sender: UITapGestureRecognizer) {
if let myIndexPath = getIndexPathForSelectedCell() {
if selectedIndex == myIndexPath.row {
selectedIndex = -1
}
else {
selectedIndex = myIndexPath.row
}
self.tableView.beginUpdates()
self.tableView.reloadRowsAtIndexPaths([myIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
self.tableView.endUpdates()
}
}
Could someone give me a clue why the indexPathsForSelectedRows returns nil?
Many Thanks!
UPDATE 1: Current Working demo
When I add my expand cell logic in didSelectRowAtIndexPath and remove my tapGestureRecognizer for the view inside the cell - it looks like this -
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if selectedIndex == indexPath.row {
selectedIndex = -1
}
else {
selectedIndex = indexPath.row
}
self.tableView.beginUpdates()
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
self.tableView.endUpdates()
}
You got this bug because
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
reloads and deselect your rows.
You just select row, after that, you reload row (this action will deselect this row) and later you want to get a selected rows using
tableView.indexPathsForSelectedRows
but table view does not have any selected rows at this moment.
As a solution, you can store selected indexPath in new variable, and use this variable instead of
tableView.indexPathsForSelectedRows
From the indexPathsForSelectedRows documentation:
The value of this property is nil if there are no selected rows.
Therefore:
guard let selectedRows = tableView.indexPathsForSelectedRows else {
return nil
}
return selectedRows[0]
(no check for count
is needed, the method never returns an empty array).
By the way, you could simplify the condition using:
return tableView.indexPathsForSelectedRows?.first
or, if your table does not support multiple selection, directly call:
return tableView.indexPathForSelectedRow
which is already there.
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