Swift handle favorite and unfavorite button based on JSON value - ios

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.

Related

When button pressed, button.setImage(nil) doesn't work

I'm trying to create Japanese crossword. Use buttons as cells. When trying to insert system image, it works (case mode 1). But when I choose other mode (2), the icon doesn't disappear.
let img1 = UIImage(systemName: "multiply"))
#IBAction func cellClicked(_ sender: UIButton) {
for cell in cellButtons {
if cell.tag == sender.tag {
switch typeCell { //when mode changes
case 1:
cell.setImage(img1, for: .normal) //work
default/*2*/:
cell.setImage(nil, for: .normal) //don't work, but running without errors
}
}
}
}
I was trying to use only sender (without if cell.tag == sender.tag; didn't work ), then create IBOutlet collection and run the code above.
Update:
I found and decide to use .isHidden. That works and I also solve my other issue :)
Thanks!

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
}

how to change UI Button shape programmatically?

I have a button that contains a finger print image like the picture above. that fingerPrint button has a function to segue to viewController2. that fingerPrint button exists on the viewController1.
when the viewController1 is opened for the first time, I will get a data from the server, if I don't have that data, I shouldn't segue to viewController2 .
but sometimes we have an error as the response of my request. if I get the error response, then I want that finger button to be rectangular button that has 'Refresh' as the title and has different function to make request again to the server
how to achieve change the shape of existing UI Button?
class ViewController1 : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
getDataFromServer()
}
#IBAction func fingerPrintButtonDidPressed(_ sender: Any) {
}
func getDataFromServer() {
// send request to get data from server
}
}
It is usually best to do it either all in code or all in storyboard. To do it in storyboard I suggest one of the following:
Create 2 buttons and in code hide one or another depending on your state
Assign different images and texts for different button states (there is a dropdown in interface builder) and then change the state of a button in runtime
To do it in code overall I suggest simply changing the values.
Assume you have something like this:
enum ViewState {
case idle
case success
case failed
}
var state: ViewState = .idle {
didSet {
refreshButton()
}
}
Now you can set your state when you get a response or on any event needed. All you need to implement is refreshButton.
func refreshButton() {
switch state {
case .idle:
button.setTitle(nil, for: .normal)
button.setImage(fingerprintImage, for: .normal)
button.backgroundColor = .clear
case .success:
button.setTitle(nil, for: .normal)
button.setImage(fingerprintImage, for: .normal)
button.backgroundColor = .clear
case .failed:
button.setTitle("REFRESH", for: .normal)
button.setImage(nil, for: .normal)
button.backgroundColor = .green
}
}
You can then use the same switch inside your button action (on press).
if isError
{
button.type = .system
button.backgroundColor - UIColor.green
button.setTitle("REFRESH" for: .normal)
button.addTarget(--------)
}
else
{
button.type = .custom
button.setImage(UIImage(named: "yourImageName.png") for: .normal)
button.addTarget(--------)
}
Simple Solution is : Use two buttons one for figure Image second for Refresh text. And use button isHidden property vice-versa.
For Auto layout
If you are using Auto layout then use constraint IBOutlet and change it's constant property value. it will change your button height or width.
For Auto resize
if you are using Auto resize than you can change you button frame which you want

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

Edit Difficulties in UICollectionViewCell with Button

I've implemented an Edit button, which adds a button to my UICollectionViewCell. When I press Edit => Edit turns into "Done" and when i press Done it is supposed to delete the Button.
My Code does allow me to add the buttons, but doesn't hide them.
Any Ideas?
#IBAction func editButton(sender: AnyObject) {
if(editButton.titleLabel?.text as String! == "Edit")
{
editButton.setTitle("Done", forState: UIControlState.Normal)
for item in self.mainCollectionView.visibleCells() as! [SettingsCollectionViewCell] {
let indexpath : NSIndexPath = self.mainCollectionView!.indexPathForCell(item as SettingsCollectionViewCell)!
let cell : SettingsCollectionViewCell = mainCollectionView!.cellForItemAtIndexPath(indexpath) as! SettingsCollectionViewCell
//Close Button
let close : UIButton = cell.collectionViewButton
close.hidden = false
}
}
else
{
editButton.setTitle("Edit", forState: UIControlState.Normal)
self.mainCollectionView?.reloadData()
}}
And cellForRowAtIndexPath:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let collectionCell:SettingsCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("collectionCell", forIndexPath: indexPath) as! SettingsCollectionViewCell
if self.editButton.titleLabel?.text as String! == "Edit"
{
collectionCell.collectionViewButton.hidden = true
}
else if editButton.titleLabel?.text as String! == "Done"
{
collectionCell.collectionViewButton.hidden = false
}
collectionCell.collectionViewButton!.layer.setValue(indexPath.row, forKey: "index")
collectionCell.collectionViewButton!.addTarget(self, action: "deletePhoto:", forControlEvents: UIControlEvents.TouchUpInside)
return collectionCell
}
You need to change the logic in cellForItemAtIndexPath for retrieving the title from the button.
In order to retrieve title text from the button you need to use titleForState(UIControlState) instead of titleLabel?.text.
Here is code snippet for conditional statement in cellForItemAtIndexPath
if self.editButton.titleForState(.Normal) == "Edit" {
collectionCell.collectionViewButton.hidden = true
}
else if self.editButton.titleForState(.Normal) == "Done" {
collectionCell.collectionViewButton.hidden = false
}
I think the best strategy here would be to create a button on the main storyboard and check 'hidden' on the button's context menu.
To change a button's text: create an outlet (yes, an outlet) for the button.
#IBOutlet var editbutton: UIButton!
Then to unhide it:
editbutton.hidden = false
(you can put this inside an if statement if desired)
Inside an action of the button (you must assign the button to an action as well) do this to hide the button if it has already been pressed into "Done":
if editbutton.title == "Done" && editbutton.hidden == false {
editbutton.hidden = true
}
Then, to change the text of the button when it still says edit:
if editbutton.title == "Edit" {
editbutton.title = "Done"
}
The actions must be done in this order, or else the button will turn into "Done" and not be hidden, so the computer will go on and hide it before the user presses it a second time.

Resources