Change value of button in an UITableViewCell is changing other button value - ios

If Too long, my problem is : When i click on the play of button of a cell and want to change the image of the pressed play button, some other cell's play button change too.
I'm creating an app where you can get Music preview and play them.
To display this, I use an UITableView with custom UITableViewCell containing a play button and some other things.
That's how it's looking.
So when i click on a Cell Play button, the right track is played but here's the problem : I try to change the backgroundImage of my button but other buttons image are changed too... And if I scroll my button even get back to the image it was using before I make the change...
The cell correctly shows the new image
But some other do it too...
And if I scroll up, my new image is remplaced by the older one...
Here's my function code :
func getPreview(sender : AnyObject){
var positionButton = sender.convertPoint(CGPointZero, toView: self.feedTable)
var indexPath = self.feedTable.indexPathForRowAtPoint(positionButton)
var rowIndex = indexPath!.row
var cell = feedTable.cellForRowAtIndexPath(indexPath!)
var bouton: UIButton = cell?.valueForKey("postPlay") as! UIButton
if sender.title == "Mettre l'extrait en pause" {
mediaPlayer.pause()
sender.setTitle("Jour l'extrait", forState: UIControlState.Normal)
var playImage = UIImage(named: "playIcon")
sender.setImage(playImage, forState: UIControlState.Normal)
}
if rowIndex == bouton.tag{
var songLink = post[rowIndex].valueForKey("previewLink") as! String
let url = NSURL(string: songLink)
mediaPlayer.contentURL = url
mediaPlayer.play()
bouton.setTitle("Mettre l'extrait en pause", forState: UIControlState.Normal)
var pauseImage = UIImage(named: "pauseIcon")
bouton.setImage(pauseImage, forState: UIControlState.Normal)
}
}
Could you help me to find what's wrong ? Thank you !

UITableViewCells are reused, not stored offscreen until you need one for the same index path again. So each time a cell is displayed, -tableView:cellForRowAtIndexPath: is called, and you're responsible for completely setting up the cell. Every time. You can't assume a state you've previously set up for a cell at that index path is still intact.

Related

Swift: Saving button image in tableView

I'm trying to save button image inside button view. Here is briefly what my code looks like:
I have a UITableView with button in it. Whenever I press the button the image changes. I change the image using this code:
First I use:
cell.checkmarkButton.addTarget(self, action:
#selector(subscribeTapped(_:)), for: .touchUpInside)
to recognize when the image is tapped. Then I use:
#objc func subscribeTapped(_ sender: UIButton) {
selectedButton = String(sender.tag)
if let ButtonImage = sender.image(for: .normal),
let Image = UIImage(named: "WhiteCheckMarkButton"),
ButtonImage.pngData() == Image.pngData()
{
sender.setImage( UIImage.init(named: "GreenCheckMarkButton"), for: .normal)
} else {
sender.setImage( UIImage.init(named: "WhiteCheckMarkButton"), for: .normal)
}
Inside my subscribeTapped function to change the image. All good it changes the image but I can't seem to find out how to save once the image has changed. It seems really confusing to me. I can definitely do it if the image is not in a tableView using UserDefaults. But inside a tableView I have no idea what should I do.

Swift 4.2 Add/Remove buttons with UICollectionViewCell

I am trying to add an UIButton to every cell in my UICollectionView when a button (outside of the UICollectionView) is pressed and then remove them when it's not.
Basically, a boolean if true - show/add, else hide/remove. This is my cellForItemAt. I also tried adding it to willDisplay cell.
let btnItemDelete = UIButton()
btnItemDelete.tag = indexPath.row
btnItemDelete.addTarget(self, action: #selector(self.btnItemDeleteClick), for: .touchUpInside) //Selector works
btnItemDelete.frame = CGRect(x: cell.bounds.width-22, y: 2, width: 20, height: 20) //Creation works
btnItemDelete.setImage(deleteImage, for: .normal) //Image works
if (isEdit) {
//Add or Show
cell.addSubview(btnItemDelete)
}
else {
//Delete or Hide
btnItemDelete.removeFromSuperview()
}
When running this, isEdit is initially set to false and the buttons do not show up. After clicking the button to change the boolean, the buttons appear. When clicking the button to set the boolean back to false, the buttons stay. I am figuring it's something with btnItemDelete.removeFromSuperview() - is there a different approach to do this? I figured I can't hide/show them because it's just going to keep adding a new button to the cell on every reload.
First you need to add to
cell.contentView not the cell
By this
btnItemDelete.removeFromSuperview()
you remove a button on the fly that's not added , instead you need
cell.contentView.subviews.forEach {
if $0.tag == 12 {
$0.removeFromSuperview()
}
}
I think the best approach is to add the button previously on the cell layout then manage it's appearance like
cell.myButton.isHidden = !isEdit

Swift handle favorite and unfavorite button based on JSON value

I am trying to implement favorite and unfavorite functionality into my cell. Here, Initially I am showing in collection view cell button icon favorite (gray), its mean unfavorite but after clicked the button it will show green, its mean favorite. From JSON I am getting response which cells are already favorite and others unfavorite icon. Its working fine but when I click JSON favorite enabled green button it’s not changing gray by single click, its working fine double click but every click I am calling JSON so 3rd click it will be add again favorite.
Here, below my code -
var checked = false
#IBAction func favoritesTapped(_ sender: Any) {
if checked {
favbutton.setImage(UIImage(named: "item_grayfav.png"), for: .normal)
checked = false
delegate?.unfavoriteButtonPressed(cell: self)
} else {
favbutton.setImage(UIImage(named: "item_greenfav.png"), for: .normal)
checked = true
delegate?.favoriteButtonPressed(cell: self)
}
}
Above code I am using for button click to change image and also initially I fixed gray checked = false
Into collection view cell at item
if indexPath.row < cfavoritesIDData.count {
if let i = cfavoritesIDData[indexPath.item] {
cell.favbutton.setImage(UIImage(named: "item_greenfav.png"), for: .normal)
}
else {
print("id is nil")
cell.favbutton.setImage(UIImage(named: "item_grayfav.png"), for: .normal)
}
}
Issues: If I click JSON enabled green button (favorite), its calling to unfavorite well but button icon not changing green after 3’rd click only its changing gray.
You need to store your cell model in your View Controller, the cell should not have a checked boolean, when you are configuring your cell in cellForRow: you should tell it there wether it is checked or not.
When pressing the button you should have a delegate callback or closure to tell the View Controller that the cell at IndexPath 'x' has pressed its favourite button and check the model as to wether or not the reaction would be checked or not, then reconfigure the cell again.
You can use the UIButton's selected property instead of checked variable:
if indexPath.row < favoritesIDData.count {
if let i = cfavoritesIDData[indexPath.item] {
cell.favbutton.setImage(UIImage(named: "item_greenfav.png"), for: .normal)
cell.favbutton.setSelected = true
}
else {
print("id is nil")
cell.favbutton.setImage(UIImage(named: "item_grayfav.png"), for: .normal)
cell.favbutton.setSelected = false
}
}
#IBAction func favoritesTapped(_ UIButton: favButton) {
if favButton.isSelected {
favbutton.setImage(UIImage(named: "item_grayfav.png"), for: .normal)
checked = false
delegate?.unfavoriteButtonPressed(cell: self)
} else {
favbutton.setImage(UIImage(named: "item_greenfav.png"), for: .normal)
checked = true
delegate?.favoriteButtonPressed(cell: self)
}
}
Note: Don't copy paste change according to correct syntax.

Toggle (Checkbox) Button in TableViewCell Swift

I'm new to iOS dev and I've been trying to toggle a button/checkbox in my tableviewcell by tapping the cell. My code is pretty naive, switching to the 'check' image works fine, but the issue is switching back to un-checked image when double tapping the cell.
What's not working in my code? Also is there a better way to do this? (perhaps via delegate funcs from the cell itself?)
Code examples would be very helpful! Thanks.
var isChecked:Bool = true
This following func is called in didSelectRowAtIndexPath func in my Tableview class.
let btnCheckBox:UIButton = cell.contactCheckbox
setState(button: btnCheckBox)
func setState(button: UIButton){
let check = UIImage(named: "check_green")
let unCheck = UIImage(named: "un_check_green")
if isChecked {
button.setImage(check, for: .normal)
isChecked = false
print("First Tap - Bool is \(isChecked)")
} else {
button.setImage(unCheck, for: .normal)
isChecked = true
print("Double Tap - Bool is \(isChecked)")
}
}
You should use UIButton , and set image for state of button, sample
check_green for selected
check_red for none
And each UITableviewcell must have an isSelected

Hide button in UICollectionView cell

I am programmatically creating cells and adding a delete button to each one of them. The problem is that I'd like to toggle their .hidden state. The idea is to have an edit button that toggles all of the button's state at the same time. Maybe I am going about this the wrong way?
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("verticalCell", forIndexPath: indexPath) as! RACollectionViewCell
let slide = panelSlides[indexPath.row]
cell.slideData = slide
cell.slideImageView.setImageWithUrl(NSURL(string: IMAGE_URL + slide.imageName + ".jpg")!)
cell.setNeedsLayout()
let image = UIImage(named: "ic_close") as UIImage?
var deleteButton = UIButton(type: UIButtonType.Custom) as UIButton
deleteButton.frame = CGRectMake(-25, -25, 100, 100)
deleteButton.setImage(image, forState: .Normal)
deleteButton.addTarget(self,action:#selector(deleteCell), forControlEvents:.TouchUpInside)
deleteButton.hidden = editOn
cell.addSubview(deleteButton)
return cell
}
#IBAction func EditButtonTap(sender: AnyObject) {
editOn = !editOn
sidePanelCollectionView.reloadData()
}
I think what you want to do is iterate over all of your data by index and then call cellForItemAtIndexPath: on your UICollectionView for each index. Then you can take that existing cell, cast it to your specific type as? RACollectionViewCell an then set the button hidden values this way.
Example (apologies i'm not in xcode to verify this precisely right now but this is the gist):
for (index, data) in myDataArray.enumerated() {
let cell = collectionView.cellForRowAtIndexPath(NSIndexPath(row: index, section: 0)) as? RACollectionViewCell
cell?.deleteButton.hidden = false
}
You probably also need some sort of isEditing Boolean variable in your view controller that keeps track of the fact that you are in an editing state so that as you scroll, newly configured cells continue to display with/without the button. You are going to need your existing code above as well to make sure it continues to work as scrolling occurs. Instead of creating a new delete button every time, you should put the button in your storyboard and set up a reference too and then you can just use something like cell.deleteButton.hidden = !isEditing

Resources