Reputation: 8671
I have a button in a cell as a toggle to check in members in a club. When I check in a member, I need the button's state to stay ON after scrolling, but it turns back off. Here is the cellForRow method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.membersTableVw.dequeueReusableCell(withIdentifier: "CellMembersForCoach", for: indexPath) as! CellMembersForCoach
let member = members[indexPath.row]
cell.setMember(member)
cell.cellController = self
return cell
}
Here is the portion in the custom cell class where I toggle the button
@IBOutlet weak var checkBtn: UIButton!
@IBAction func setAttendance(_ sender: Any){
// toggle state
checkBtn.isSelected = !checkBtn.isSelected
}
The toggling works but after scrolling the table, the button state changes back to original. Any suggestion is appreciated.
Upvotes: 0
Views: 1890
Reputation: 8671
Shamas highlighted a correct way to do it, so I'll share my whole solution.
I created a singleton class to store an array of checked cells:
class Utility {
// Singleton
private static let _instance = Utility()
static var Instance: Utility{
return _instance
}
var checkedCells = [Int]()
In the custom cell class I have action method wired to the check button to add and remove checked cells:
@IBOutlet weak var checkBtn: UIButton!
@IBAction func setAttendance(_ sender: Any){
// Get cell index
let indexPath :NSIndexPath = (self.superview! as! UITableView).indexPath(for: self)! as NSIndexPath
if !checkBtn.isSelected{
Utility.Instance.checkedCells.append(indexPath.row)
}else{
// remove unchecked cell from list
if let index = Utility.Instance.checkedCells.index(of: indexPath.row){
Utility.Instance.checkedCells.remove(at: index)
}
}
// toggle state
checkBtn.isSelected = !checkBtn.isSelected
}
In the cellForRowAt method in the view controller I check if the cell row is in the array and decide if the toggle button should be checked:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.membersTableVw.dequeueReusableCell(withIdentifier: "CellMembersForCoach", for: indexPath) as! CellMembersForCoach
if Utility.Instance.checkedCells.contains(indexPath.row){
cell.checkBtn.isSelected = true
}
return cell
}
Upvotes: 1
Reputation: 936
Since the tableView is reusing cells you code is not going to work. You have to keep track of each button when selected and set it again when tableview is reusing cells when you scroll. Solution : You can take an array(contains bool) which is size of your tableview data. So you have to set state of button using array and update array when selected or deselected.
Upvotes: 0
Reputation: 684
This is because of tableview is reusing your cell. so you have to maintain button as per tableView data source.
Upvotes: 3
Reputation: 535
The problem is here:
checkBtn.isSelected = !checkBtn.isSelected
This code will reflect the button selection state every time the cell is configured when the delegate cellForRowAt
invokes. So if you selected it before, now it turns to not-selected.
Upvotes: 0
Reputation: 7549
This happens because you are reusing the cells.
You need to keep track of which cells have been selected. Perhaps in your member's class. Then when you are in your cellForRowAt
you should check if this cell has been selected before and set the correct state for your button.
Upvotes: 4