Toggle (Checkbox) Button in TableViewCell Swift - ios

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

Related

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

IOS/Swift: check for button image to toggle button image

I am just learning Swift and am trying to toggle a button based on a user action between two images. It would be nice to just check the name of the images showing and toggle to the other one.
I am able to get the image from the button but not necessarily it's name. My question is how to compare it to the image name in Swift.
func toggleImage(){
var img = self.sendButton.image(for: .normal)//NO ERROR
if img.isEqual(image-one) {
//ERROR HERE
//switch to image-two
} else {
//switch to image-one
}
}
Thanks in advance for any suggestions.
There is a better way. Treat the button like a checkbox. The unchecked state is image 1, the checked state is image 2.
To setup a UIButton to work like a checkbox, use the isSelected property.
sendButton.setImage(UIImage(named: "image1"), for: .normal)
sendButton.setImage(UIImage(named: "image2"), for: .selected)
// You may also need to set the image for the highlighted selected state.
sendButton.setImage(UIImage(named: "image2"), for: [.selected, .highlighted])
Now that the button knows about both images, you can switch between the to using the isSelected property.
func toggleImage() {
sendButton.isSelected = !sendButton.isSelected
}
Using ===
private let image-one = UIImage(named: "name1")
private let image-two = UIImage(named: "name2")
override func viewDidLoad() {
sendButton.setImage(image-one, for: .normal)
}
func toggle image() {
if self.sendButton.currentImage === image-one {
.....
}
}
Using flags (less elegant, but much safer):
enum WhichImage {
case image-one, image-two
}
private var whichImage: WhichImage = .image-one
Instead of checking images you check whichImage and update it when image is changed.
Set Images in Interface approach the just change state of button in code.
Here is the code to change the state
#IBAction func fastButtonAction(_ sender: Any) {
fastButton.isSelected = !fastButton.isSelected
}
You need to get image name and compare it like below
if self.sendButton.currentImage == UIImage(named: "image-one") {
//switch to image-two
}else {
//switch to image-one
}

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.

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

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

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.

Resources