Search code examples
iosswiftuitableviewsections

Change rows button image source on click?


I am trying to implement code for changing a row's button image source on click of the row. This is for a checklist table view.The table view is split into sections. Not sure what I'm doing wrong:

 func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    //change tickBtn's image src to tick.png
    print("in didselect")
    if let cell = tableView.cellForRowAtIndexPath(indexPath) as? CheckListCell {
        let tickedImg = UIImage(named: "tick.png")
        cell.tickBtn.setImage(tickedImg, forState: UIControlState.Selected)
        //cell.tickBtn.alpha = 0

    }
    else{
        print("in the else of didSelect")
    }

}

func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
    //change tickBtn's image src to unTicked.png
    print("in didDeselect")
    if let cell = tableView.cellForRowAtIndexPath(indexPath) as? CheckListCell{
        let tickedImg = UIImage(named: "unTicked.png")
        cell.tickBtn.setImage(tickedImg, forState: UIControlState.Selected)
        //cell.tickBtn.alpha = 1
    }
    else{
        print("in the else of didDeSelect")
    }

}

I'm getting the logs for didSelect and didDeSelect but the image source is not changing. Must be something to do with how i'm accessing the cell and I need to take into account the section?

UPDATE:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    //change tickBtn's image src to tick.png
    let cell = tableView.cellForRowAtIndexPath(indexPath) as? CheckListCell
    cell!.cellTickedImage = UIImage(named: "tick.png")
    self.checkListTableView.beginUpdates()
    self.checkListTableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
    self.checkListTableView.endUpdates()

}

func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
    let cell = tableView.cellForRowAtIndexPath(indexPath) as? CheckListCell
    cell!.cellTickedImage = UIImage(named: "unTicked.png")
    self.checkListTableView.beginUpdates()
    self.checkListTableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
    self.checkListTableView.endUpdates()
}

class CheckListCell : UITableViewCell {

    @IBOutlet weak var tickBtn: UIButton!
    @IBOutlet weak var taskLbl: UILabel!
    var cellTickedImage : UIImage?

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = checkListTableView.dequeueReusableCellWithIdentifier("CheckListCell", forIndexPath: indexPath) as! CheckListCell

        cell.taskLbl?.text = checkListData[indexPath.section][indexPath.row]
        cell.tickBtn.setImage(cell.cellTickedImage, forState: UIControlState.Normal)
        cell.tickBtn.setImage(cell.cellTickedImage, forState: UIControlState.Highlighted)

        //cell.tickBtn.titleLabel!.text = ""

        return cell
    }

Solution

  • Try this out:

    Step 1 : In didSelectRowAtIndexPath update the model that drives cell image:

    self.cellTickedImage = UIImage(named: "tick.png”)
    

    Step 2 : In didSelectRowAtIndexPath reload the cell to see the change:

    self.tableView.beginUpdates()
    self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
    self.tableView.endUpdates()
    

    Step 3 : In didDeselectRowAtIndexPath update the model that drives cell image:

    self.cellTickedImage = UIImage(named: "unTicked.png”)
    

    Step 4 : In didDeselectRowAtIndexPath reload the cell to see the change:

    self.tableView.beginUpdates()
    self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
    self.tableView.endUpdates()
    

    Step 5 : In cellForRowAtIndexPath set the cell image correctly:

    cell.tickBtn.setImage(self.cellTickedImage, forState: UIControlState.Normal)
    cell.tickBtn.setImage(self.cellTickedImage, forState: UIControlState.Highlighted)
    

    EDIT: Post discussion with OP on chat - Few assumptions from discussion

    1. No two cells shall have same text on it.
    2. On one tap show one image and on second tap show second image.

    Considering this, here is the high level algorithm for the fix:

    1. Create a global dictionary checkListDict with key as cell text and value as image status flag. Initially set value is 0 for all cell text. Considering 1 as tick.png and 0 as unTicked.png.
    2. In didSelectRowAtIndexPath update the flag like this:

    ->

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
       //change tickBtn's image src to tick.png 
       let cell = tableView.cellForRowAtIndexPath(indexPath) as? CheckListCell 
       let selectedCellText = (cell!.taskLbl?.text)!
    
       if checkListDict[selectedCellText] == 0 { 
          checkListDict[selectedCellText] = 1 
       } 
       else{ 
          checkListDict[selectedCellText] = 0 
       } 
    
       self.checkListTableView.beginUpdates() 
       self.checkListTableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) 
       self.checkListTableView.endUpdates()
    }
    
    1. Finally, use the updated model in cellForRowAtIndexPath like this:

    ->

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = checkListTableView.dequeueReusableCellWithIdentifier("CheckListCell", forIndexPath: indexPath) as! CheckListCell
    
        let selectedCellText = checkListData[indexPath.section][indexPath.row]
    
        cell.taskLbl?.text = selectedCellText
        let cellImage = checkListDict[selectedCellText] == 0 ? UIImage(named: "unTicked.png")  : UIImage(named:"tick.png") 
    
    
        cell.tickBtn.setImage(cellImage, forState: UIControlState.Normal)
        cell.tickBtn.setImage(cellImage, forState: UIControlState.Highlighted)
    
        return cell
    }