2

I'm trying to change the color of a button when pressed. Currently its inside a table view cell.

The way I'm doing it is adding as so:

@IBAction func upVote(sender: AnyObject) {
        sender.setImage(UIImage(named: "bUpVote"), forState: .Normal)
    }

and this is done inside the cell class (not the view controller class).

It works, but the change also applies to every third cell that follows it for the rest of the table. Any work around? Thanks!

Shamas S
  • 7,507
  • 10
  • 46
  • 58
Chris Jones
  • 856
  • 1
  • 11
  • 24

3 Answers3

1

There are many way to solve this issue, one of the method is as follows

Add this to your customCell class,

@objc protocol MyTableViewCellDelegate {
func controller(controller: MyTableViewCell, button: UIButton, selectedButtonIndexPath : NSIndexPath)
}


class MyTableViewCell: UITableViewCell {
var delegate: AnyObject?
var indexPath : NSIndexPath?
@IBOutlet weak var button: UIButton!//outlet of button

button Action

@IBAction func buttonAction(sender: UIButton)//IF the sender type is AnyObject, you have to change it as UIButton
{
    self.delegate?.controller(self,  button: sender, selectedButtonIndexPath: indexPath!)
}

Add this to your ViewController class that has UITableView

 class MyTableViewController: UITableViewController, MyTableViewCellDelegate {  // I created a subClass of UITableViewController, your's may be different
var arraySelectedButtonIndex : NSMutableArray = []//global declaration

Since i created my custom cell using xib, in viewDidLoad()

tableView.registerNib(UINib(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomCell")//Since, I use custom cell in xib

define delegate of custom cell by adding this

func controller(controller: MyTableViewCell, button: UIButton, selectedButtonIndexPath : NSIndexPath)
{
    if(arraySelectedButtonIndex .containsObject(selectedButtonIndexPath)==false)
    {
        arraySelectedButtonIndex.addObject(selectedButtonIndexPath)
        button.setImage(UIImage(named: "bUpVote")  , forState: .Normal)
    }
    else
    {
        arraySelectedButtonIndex.removeObject(selectedButtonIndexPath)//If you need to set Deselect image
        button.setImage(UIImage(named: "deselectImage") , forState: .Normal)//If you need to set Deselect image
    }
}

In tableView dataSource (cellForRowAtIndexPath)

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! MyTableViewCell
    cell.delegate = self
    cell.indexPath = indexPath
    if(arraySelectedButtonIndex .containsObject(indexPath))
    {
        cell.button.setImage(UIImage(named: "bUpVote"), forState: .Normal)
    }
    else
    {
        cell.button.setImage(UIImage(named: "deselectImage"), forState: .Normal)//If you need to set Deselect image
    }
    return cell
}
Shebin Koshy
  • 1,182
  • 8
  • 22
  • THANK YOU! This works perfect. I have a question though: I have a second button in the same cell that must change every time the first button is clicked (the downvote button). I see that you're sending the clicked button with "button: sender!" but how would I pass through the other button? – Chris Jones Sep 07 '15 at 21:27
  • @ChrisJones You have to create another function like `func controller(controller: MyTableViewCell, **button2**: UIButton, selectedButtonIndexPath : NSIndexPath)` or another way is, globally declare `downVoteButton` and pass through the existing function as a parameter.. – Shebin Koshy Sep 08 '15 at 03:33
0

It's because cells are reused by the tableView. if you need to persist the state of subviews in the cell, you need to update your data source and reflect the changes in cellForRowAtIndexPath method.

Prajeet Shrestha
  • 7,978
  • 3
  • 34
  • 63
0

This is not the way to do it. You store the state of the button in your model. Eg: say store the item's upvoted status in your model :

class Post
{
var title : String
var upvoted : Bool
}

How to get the index path ?

Move the IBAction method on your custom tableview subclass. Add a property called delegate to the cell and set it to your controller in cellForRowAtIndexPath: . Now in the action method inform the delegate.

I have described this in detail here : https://stackoverflow.com/a/32250043/1616513

Now when the user upvotes you update the model :

@IBAction func upVotedInCell(sender: UITableViewCell) {

     var indexPath = self.tableView.indexPathForCell(sender)

     self.items[indexPath].upvoted = true

     self.tableView.reloadRowsAtIndexPaths([indexPath],UITableViewRowAnimation.None)
}
Community
  • 1
  • 1
Samhan Salahuddin
  • 2,140
  • 1
  • 17
  • 24