I'm trying to set an image for a button's normal state which is located in a collectionView cell. When the button is pressed the image changes. The problem is every four cells it repeats the same image as the original cell when the button is pressed. Is there a way to not have it repeat itself and when the button is pressed its only for that individual cell?
Here is the code:
class FavoritesCell: UICollectionViewCell {
var isFavorite: Bool = false
@IBOutlet weak var favoritesButton: UIButton!
@IBAction func favoritesButtonPressed(_ sender: UIButton) {
_ = self.isFavorite ? (self.isFavorite = false, self.favoritesButton.setImage(UIImage(named: "favUnselected"), for: .normal)) : (self.isFavorite = true, self.favoritesButton.setImage(UIImage(named: "favSelected"), for: .selected))
}
}
I've tried doing this but for some strange reason the 'selected' state image is never shown even when the button is pressed:
let button = UIButton()
override func awakeFromNib() {
super.awakeFromNib()
button.setImage(UIImage(named: "favUnselected"), for: .normal)
button.setImage(UIImage(named: "favSelected"), for: .selected)
}
Every time your cell is dequeued
cellForItemAt
is called. This is the place where you configure your cell data. So if you need to show cell marked as favourite, you can do it here.So how do you do it there? Let's say all your cells are not selected in the beginning. Fine. You don't have to say anything in
cellForItemAt
. Now let's say you mark a few cells as favourite. What happens here is, it will reflect the change when the cell is visible because the button is hooked to a selector which will make the changes.Now here is the problem. When you scroll and the cell disappears, the information about your cell being marked as favourite is lost! So what you need to do, is maintain an array which will store the
IndexPath
of all the selected cells. (Make sure to remove theIndexPath
when a cell is removed from favourite!) Let's call that arrayfavourites
. If you can use your data source for the collection view to store the selected state information that is also fine. Now you have to store the information about whether your cell is marked as favourite in your button selector.After you have stored the information about the cell, every time you dequeue a cell, you need to check if the
IndexPath
isfavourites
. If it is, you call a method which sets the cell in the selected state.Done? No! Now we have another problem. This problem is associated with the reuse of the cell. So what happens in
cellForItemAt
actually? You dequeue a cell and use it to display information. So when you dequeue it what happens is, it might have already been used for showing some other information in some other index path. So all the data that was existing there will persist. (Which is why you have the problem of favourites repeating every 4 cells!)So how do we solve this? There is method in
UICollectionViewCell
which is called before a cell is dequeued -prepareCellForReuse
. You need to implement this method in your cell and remove all the information from the cell, so that it is fresh when it arrives atcellForItemAt
.Or you could always set every value of everything inside the cell in
cellForItemAt
so that every information is always overwritten with the necessary value.Edit: OP says he has a collection view inside a collection view. You can identify which collection view is called like this,
The cell is most likely reused and your
isFavorite
is set totrue
.Just try adding
This will set the button to original image when cell is to be reused.
Also since you have your button have two states for
selected
why do this dancewhere you could only say
self.favoritesButton.selected = self.isFavorite
Change your cell code to: