Tunds
Tunds

Reputation: 1817

TableViewCell button click firing in multiple sections of TableViewControl

Bit of a weird one i can't seem to understand so i have a tableview control in a viewcontroller and within the tableviewcell i have a button which is using a delegate.

So when the button is clicked it will change the tag number of the cell and also change the image of the button based on the tag of the cell in the tableview.

But the problem i'm having is that when you select a button in a row i.e. the first one it seems to be running the function to change the image for each item in a section almost. I.e choosing the 5th item will update every 5th button in a cell to the selected image which is weird. Since it's almost like the tableview is being split up to sections of 5.

Can anyone help prevent this behaviour so it only changes the icon for the button in the cell which has been pressed.

Below are the functions that i've used and a link to a video on dropbox showing the behaviour https://www.dropbox.com/s/a4aasti78872w6j/Help.mov?dl=0

Delegate

protocol StoryTableViewCellDelegate: class {

    func didBookmarkItem(cell: StoryTableViewCell, sender: AnyObject)

}

Function for Delegate

@IBAction func bookmarkButtonDidTouch(sender: AnyObject) {

    bookmarkButton.animation = "pop"
    bookmarkButton.curve = "easeOut"
    bookmarkButton.duration = 0.5
    bookmarkButton.damping = 0.4
    bookmarkButton.velocity = 0.4
    bookmarkButton.animate()

    // The delegate which will handle bookmarking items
    delegate?.didBookmarkItem(self, sender: sender)

}

Function being used in tableview class

// MARK: StoryTableViewDelegate
func didBookmarkItem(cell: StoryTableViewCell, sender: AnyObject) {

    // TODO: Implement bookmark functionality
    switch cell.bookmarkButton.tag {

    case 0:
        cell.bookmarkButton.setImage(UIImage(named: "Bookmark-Selected"), forState: UIControlState.Normal)
        cell.bookmarkButton.tag = 1


    case 1:
        cell.bookmarkButton.setImage(UIImage(named: "Bookmark-Not-Selected"), forState: UIControlState.Normal)
        cell.bookmarkButton.tag = 0
    default:
      break
    }
}

Upvotes: 1

Views: 651

Answers (3)

mbeaty
mbeaty

Reputation: 1559

As others have said, it's due to table cell reuse. You want your tableView(_:cellForRowAtIndexPath:) method to always update the cell state from your model. Your bookmark state should be a property of your model. When the bookmark button state for a cell is changed by the user, the new state should be reflected in your model. If you do these things, your table cell state will always be correct. If you don't already, it's nice to always define a custom UITableViewCell class that contains outlets for all of the views and controls within your table view cell (your bookmark button would have an outlet.) Also, within your custom cell class, when you capture the button selection, you can call back to the controller either via a delegate (as you are doing), or a "bookmarkChanged" handler (closure) defined on the cell. I prefer the closure method. If you would like to see an working example of this, let me know.

Also, nix the tag. You don't need the tag to keep track of your bookmark button selection state, unless there's more to it than you have shown/described. If you follow the approach I described, it's taken care of.

Upvotes: 1

Glenn
Glenn

Reputation: 2806

The reason is, you are probable creating a cell using :

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

        let cell = tableView.dequeueReusableCellWithIdentifier("cellID")
...

like you should do. However dequeueReusableCellWithIdentifier re-uses a cell, so if you have changed anything in a cell (like adding buttons), those buttons will still be in that recycled cell.

So you must set the book mark status in your cellForRowAtIndexPath for each cell.

I once had a similar problem when adding buttons to a cell, and when scrolling the cells automatically had extra buttons. So the first thing I did when re-using a cell was remove all buttons.

Edit sample code

in your

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)

you have to add code for setting the button to the desired state, it will be something similar to the code you're using in didBookMarkItem :

switch myProperty {

    case 0:
        cell.bookmarkButton.setImage(UIImage(named: "Bookmark-Selected"), forState: UIControlState.Normal)
        cell.bookmarkButton.tag = 1


    case 1:
        cell.bookmarkButton.setImage(UIImage(named: "Bookmark-Not-Selected"), forState: UIControlState.Normal)
        cell.bookmarkButton.tag = 0
    default:
      break
    }

You'll need a myProperty variable of course, which you should change in your didBookMarkItem as well

Upvotes: 1

Ishan Handa
Ishan Handa

Reputation: 2281

Table view cells are reused. Once you select a cell and change its tag number and scroll the selected cell out of the table view, it will be used again to show a row at the index path of the new row that appears. And since its tag represents that of a selected cell it is displayed as highlighted.

Try to look up about cell reuse in table views.

You need to change your approach about determining which cell is to be displayed as selected. Add it as a property in your data source and based on that set the bookmark as selected or not selected.

Upvotes: 0

Related Questions