Reputation: 512
I'm trying to create a checkbox functionality in a tableview . It's a to-do list where if the checkbox is pressed the cell hides and appears as completed in a different section.
Coming from C# this was very straightforward to do but in swift there isn't even a checkbox button to start with :(...
I made it to work by adding a button with two images(checked, unchecked) to a custom prototype cell in IB. Since you can't have the tableView and the in-cell-button declared in the same viewcontroller/class I had to subclass the tableViewCell.
Now, how do I access the checkbox from didSelectRowAtIndexPath
? When I select the cell the event fires but when I press the checkbox button in the same cell nothing fires and I can't hide the cell.
var indexTag = checkBoxImage.tag
//this is what I have in TableViewCell class
@IBAction func checkBoxInCell(sender: UIButton) {
checkBoxImage.setImage(UIImage(named:"checked"),forState:UIControlState.Normal)
if isChecked != false {
isChecked = false
cellitemcontent.removeAtIndex(indexTag)
//can't access the cell from here to update the tableview
}
else {
isChecked = true
checkBoxImage.setImage(UIImage(named:"unchecked"),forState:UIControlState.Normal)
}
}
//this is what I have in my FirstViewController that contains the tableview
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
cellitemcontent.removeAtIndex(indexTag)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
//when I press the checkBoxImage button in the cell it doesn't fire this event...
}
Upvotes: 0
Views: 6070
Reputation: 176
I use sample code below to implement check box button in cell (Xcode 7/ Swift 2.0):
-In viewDidLoad {}:(save check box state in each cell to .plist file)
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let fnstring = (documentsPath as String)+"/yr-filename.plist"
let fM = NSFileManager.defaultManager()
//if (let a != (fM.fileExistsAtPath(fnstring))) {
if !(fM.fileExistsAtPath(fnstring)) {
let onlyarr = NSMutableArray()
for var i = 0 ; i < 5; ++i{ // number of sections
var arr = NSArray()
switch i { // number cell in each section
case 0: arr = [Int](count: 12, repeatedValue: 0) // 0 means unchecked box.
case 1: arr = [Int](count: 13, repeatedValue: 0)
case 2: arr = [Int](count: 14, repeatedValue: 0)
case 3: arr = [Int](count: 15, repeatedValue: 0)
case 4: arr = [Int](count: 16, repeatedValue: 0)
default: arr = [Int]()
}
onlyarr.addObject(arr)
}
onlyarr.writeToFile(fnstring, atomically: false)
}
- In override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { }
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let fnstring = (documentsPath as String)+"/yr-filename.plist"
let fM = NSFileManager.defaultManager()
if fM.fileExistsAtPath(fnstring) {
let chcklstDick = NSMutableArray(contentsOfURL: NSURL(fileURLWithPath: fnstring))
let chcklstsortedCat: NSArray? = chcklstDick
let ttt: NSMutableArray = chcklstsortedCat?.objectAtIndex(indexPath.section) as! NSMutableArray
if ttt.count > 0 {
var img = UIImage()
let j : Int = ttt.objectAtIndex(indexPath.row) as! Int
NSLog("j: %i", j)
if j > 0 {
img = UIImage(named: "checked")!
}else {
img = UIImage(named: "unchecked")!
}
let bttn : UIButton = UIButton(type: UIButtonType.Custom)
bttn.frame = CGRectMake(0, 0, img.size.width, img.size.height)
bttn.setBackgroundImage(img, forState: UIControlState.Normal)
bttn.addTarget(self, action:"chckBttnTapped:eventy:", forControlEvents: UIControlEvents.TouchUpInside)
cell.accessoryView = bttn
}
}else {NSLog("nonononononononno")}
- In func chckBttnTapped(sender: AnyObject, eventy event: AnyObject) { }
let touches: NSSet = event.allTouches()!
let touch: UITouch = touches.anyObject()! as! UITouch
let crrntTouchPos : CGPoint = touch.locationInView(self.tableView)
let idxpth: NSIndexPath = self.tableView.indexPathForRowAtPoint(crrntTouchPos)!
if idxpth.row != NSNotFound {
self.tableView(self.tableView, accessoryButtonTappedForRowWithIndexPath: idxpth)
}
-In override func tableView(tableView: UITableView, accessoryButtonTappedForRowWithIndexPath indexPath: NSIndexPath) { }
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let fnstring = (documentsPath as String)+"/yr-filename.plist"
let fM = NSFileManager.defaultManager()
if fM.fileExistsAtPath(fnstring) {
let chcklstDick = NSMutableArray(contentsOfURL: NSURL(fileURLWithPath: fnstring))
let chcklstsortedCat: NSMutableArray? = chcklstDick
let ttt: NSMutableArray = chcklstsortedCat?.objectAtIndex(indexPath.section) as! NSMutableArray
if ttt.count > 0 {
let j : Int = ttt.objectAtIndex(indexPath.row) as! Int
var newimg = UIImage()
if j == 0 {
newimg = UIImage(named: "checked")!
}else {
newimg = UIImage(named: "unchecked")!
}
let cell = tableView.dequeueReusableCellWithIdentifier("cellID", forIndexPath: indexPath)
let bttn : UIButton = UIButton(type: UIButtonType.Custom)
bttn.frame = CGRectMake(0, 0, newimg.size.width, newimg.size.height)
bttn.setBackgroundImage(newimg, forState: UIControlState.Normal)
bttn.addTarget(self, action:"chckBttnTapped:eventy:", forControlEvents: UIControlEvents.TouchUpInside)
cell.accessoryView = bttn
self.tableView.reloadData()
self.tableView.reloadInputViews()
ttt.replaceObjectAtIndex(indexPath.row, withObject: 1 - j)
chcklstsortedCat?.replaceObjectAtIndex(indexPath.section, withObject: ttt)
chcklstsortedCat?.writeToFile(fnstring, atomically: false)
}
}
Hope its useful.
Upvotes: 2
Reputation: 2881
I know what you are trying to accomplish, but I would tackle it a different way. Perhaps in your model, you could have an array of tasks that are pending, and another array of tasks that are completed.
The number of sections can be 2. The number of rows in sections 0 and 1 can be the number of elements in the first and second arrays respectively.
When didSelectRowAtIndexPath
is called, you can remove the item at that index in the first array and add the task to the second array. Then you must call tableView.reloadData()
.
I know you want to just pick up the row and change the placement of it, but in iOS the cells get reused. It's best to update the data source and then reload the table.
For the checkmarks, you can ensure that the items in Section 0 do not have the checkmark accessory, while the items in Section 1 do. You would set the accessory in cellForRowAtIndexPath
after the cell has been dequeued.
Upvotes: 0