Reputation: 25
The goal of the UITableView is to display names with a custom styled checkbox beside it. But somehow when I tap the checkbox, multiple checkboxes in the UITableView get selected.
I've googled and implemented multiple solutions from different questions but none of them seem to work.
Custom UITableViewCell
import UIKit
class NameTableViewCell: UITableViewCell {
var name = UILabel()
let checkboxImage_unchecked = UIImage(named: "cellViewCheckbox_unchecked")
let checkboxImage_checked = UIImage(named: "cellViewCheckbox_checked")
let checkbox:UIButton
weak var delegate:HandleCellInteractionDelegate?
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
self.checkbox = UIButton(frame: CGRectMake(35, 16, self.checkboxImage_unchecked!.size.width/2, self.checkboxImage_unchecked!.size.height/2))
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.backgroundColor = UIColor.transparant()
self.checkbox.setBackgroundImage(self.checkboxImage_unchecked, forState: .Normal)
self.checkbox.setBackgroundImage(self.checkboxImage_checked, forState: .Selected)
self.name = UILabel(frame: CGRectMake(97,18,200, 30))
self.addSubview(self.name)
self.addSubview(self.checkbox)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func checkboxPushed(sender:AnyObject){
self.checkbox.selected = !self.checkbox.selected
self.delegate?.didPressButton(self)
}
In the protocol I declare a method didPressButton as a callback for when the button is pressed (the delegate needs to implement it)
Protocol
import UIKit
protocol HandleCellInteractionDelegate:class {
func didPressButton(cell:NameTableViewCell)
}
The ViewController
import UIKit
class NameViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, HandleCellInteractionDelegate{
var nameView:NameView {
get {
return self.view as! NameView
}
}
var names:[Name]?
var firstLetters:[String]?
let cellIdentifier = "nameCell"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//self.view.backgroundColor = UIColor.darkSalmon()
}
override func loadView() {
let bounds = UIScreen.mainScreen().bounds
self.view = NameView(frame: bounds)
if(NSUserDefaults.standardUserDefaults().objectForKey("gender") !== nil){
self.loadJSON()
self.getFirstLetters();
self.nameView.tableView.delegate = self;
self.nameView.tableView.dataSource = self;
self.nameView.tableView.registerClass(NameTableViewCell.classForCoder(), forCellReuseIdentifier: "nameCell")
self.nameView.tableView.separatorStyle = .None
self.nameView.tableView.rowHeight = 66.5 }
}
func loadJSON(){
let path = NSBundle.mainBundle().URLForResource("names", withExtension: "json")
let jsonData = NSData(contentsOfURL: path!)
self.names = NamesFactory.createFromJSONData(jsonData!, gender: NSUserDefaults.standardUserDefaults().integerForKey("gender"))
}
func getFirstLetters(){
var previous:String = ""
for name in self.names! {
let firstLetter = String(name.name.characters.prefix(1))
if firstLetter != previous {
previous = firstLetter
self.firstLetters?.append(firstLetter)
print(firstLetter)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (self.names!.count)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return nameCellAtIndexPath(indexPath)
}
func nameCellAtIndexPath(indexPath:NSIndexPath) -> NameTableViewCell {
let cell = self.nameView.tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! NameTableViewCell
self.setNameForCell(cell, indexPath: indexPath)
cell.delegate = self;
cell.checkbox.addTarget(cell, action: "checkboxPushed:", forControlEvents: .TouchUpInside)
return cell
}
func setNameForCell(cell:NameTableViewCell, indexPath:NSIndexPath) {
let item = self.names![indexPath.row] as Name
cell.name.text = item.name
}
func didPressButton(cell: NameTableViewCell) {
print(cell)
}
}
What am I doing wrong & how can I fix it?
Upvotes: 0
Views: 809
Reputation: 1390
You must have to save the check box state. Add one more attribute say checkboxStatus to your Model(Name).I hope you will have indexpath.row. After this line in nameCellAtIndexPath
cell.delegate = self;
set the tag like this
cell.tag = indexPath.row;
In the delegate method,
func didPressButton(cell: NameTableViewCell) {
print(cell)
let item = self.names![cell.tag] as Name
item.checkboxstatus = cell.checkbox.selected
}
Just one crucial change,
func nameCellAtIndexPath(indexPath:NSIndexPath) -> NameTableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! NameTableViewCell
self.setNameForCell(cell, indexPath: indexPath)
cell.delegate = self;
cell.tag = indexPath.row;
cell.checkbox.addTarget(cell, action: "checkboxPushed:", forControlEvents: .TouchUpInside)
let item = self.names![cell.tag] as Name
cell.checkbox.selected = item.checkboxstatus
return cell
}
Cheers!
Upvotes: 2
Reputation: 2259
This happens because the UITableViewCell are being reused.
You changed the cell when you press the checkbox, you need to keep track of that in your data source model.
In cellForRowAtIndexPath
you have to add a condition to check if that checkbox was checked or not. Then you display the appropriate view accordingly.
Edit:
In your example you need to check in nameCellAtIndexPath
if the checkbox is checked or not and then display it correct.
Upvotes: 0