Implementing A Favorite Button Swift - ios

I Would like to implement a Favorite button in my detailVC.
I Have a tableView with a list of restaurants in the area :
ResterauntTableViewController:
import UIKit
class ResterauntViewController: UITableViewController,UISearchResultsUpdating,UISearchBarDelegate,UISearchDisplayDelegate{
#IBOutlet var tableViewController: UITableView!
// MARK : Data
var names = ["Shalvata",
"Markid",
"Litzman Bar",
"The Cat & The Dog",
"Light house",
"Ku"]
it looks like this :
Each cell has a DetailViewController and a favorite button i wish to create.
I have already set up a button that is changing the image if i click on the button and vice versa right here :
override func viewDidLoad() {
super.viewDidLoad()
//create a new button
let Favoritebutton: UIButton = UIButton(type: UIButtonType.Custom)
//set image for button
Favoritebutton.setImage(UIImage(named: "EmptyHeart.png"), forState: UIControlState.Normal)
Favoritebutton.setImage(UIImage(named: "FilledHeart.png"), forState: UIControlState.Selected)
//add function for button
Favoritebutton.addTarget(self, action: #selector(self.button(_:)), forControlEvents: .TouchUpInside)
//set frame
Favoritebutton.frame = CGRectMake(90, 90, 35, 35)
let barButton = UIBarButtonItem(customView: Favoritebutton)
//assign button to navigationbar
self.navigationItem.rightBarButtonItem = barButton
}
#IBAction func button(sender: UIButton) {
sender.selected = !sender.selected;
}
}
Once Favorite button is clicked i want to show the item wish was clicked and set as favorite to show in another tab ( i have a tab bar project )
and of course when i quit the app it will remember my favorites.
i managed to do the button myself but i don't know how to create the favorite function so i would like to get some help.I couldn't find any good tutorial showing any of it either.
Thanks for helping.

It is very broad question you are asking...
You need some kind of persistence to save the like button action. I recommend using SQLite or Core Data to store it, and then you can read it on the FavoriteTab
Here is a very good tutorial SQLite Tutorial: Getting Started
Here is a very good tutorial on User Defaults

Related

how to add element using swift to a storyboard stackview

I am a beginner so sorry if it is a stupid question but I am trying to add new elements to a stack view that was made with a storyboard. I want to do it every time a button was pressed and I want the same color, size, constraint... how do I do this?
here is an image of my code
and this is the image of my storyboard structure
and this is what I made with the storyboard
and I want to add another button like the other ones every time the settings button is pressed
pls, can anyone help?
Connect your stack view to an #IBOutlet such as:
#IBOutlet var stackView: UIStackView!
Instead of trying to "copy" the button you designed in Storyboard, use a function to create a new button with your desired properties:
func makeNewButton() -> UIButton {
// create a button
let b = UIButton()
// set your desired font
b.titleLabel?.font = .systemFont(ofSize: 18.0, weight: .light)
// set background color to your desired light-green
b.backgroundColor = UIColor(red: 0.0, green: 0.85, blue: 0.0, alpha: 1.0)
// set title colors for normal and highlighted
b.setTitleColor(.white, for: .normal)
b.setTitleColor(.gray, for: .highlighted)
return b
}
Now, your function for tapping the "Settings" button could look like this:
#IBAction func settingsButtonPressed(_ sender: Any) {
// call func that returns a new button with your
// desired colors, font, etc
let newButton = makeNewButton()
// set the title (presumably you'll be getting a new title string from somewhere)
newButton.setTitle("New Button", for: [])
// give it an action
newButton.addTarget(self, action: #selector(self.btnTapped(_:)), for: .touchUpInside)
// add it to the stack view
stackView.addArrangedSubview(newButton)
}
Edit the above code assumed an existing function for handling the button action - such as:
#objc func btnTapped(_ sender: UIButton) {
// do something when the button is tapped
print("A button was tapped...")
}

UIButton not toggling between two images Swift 4.2

I am wanting to add sounds to my app. I have added a UIButton with two images, soundON and soundOFF.
When I call the sound settings in the app the first time, they toggle fine with each image.
However, when I return to the sound settings a second and subsequent time, it is like the soundOff images does not disappear when the soundOn image is displayed.
Odd as the code is so short and simple.
func soundButton() {
sounds = UIButton(frame : CGRect(x: 65, y: 70, width: 40, height:40))
sounds.setImage(UIImage(named : "soundON"), for : .normal)
sounds.setImage(UIImage(named : "soundOFF"), for : .selected)
sounds.showsTouchWhenHighlighted = true
sounds.addTarget(self, action: #selector(soundButtonTapped), for: .touchUpInside)
self.soundView.addSubview(sounds)
}
#objc func soundButtonTapped(_ sender: Any) {
sounds.isSelected.toggle()
isSoundOn.toggle()
}
I have added a video to show the issue as this will save a ton of typing.
http://www.reeflifeapps.com/soundError.mov
Any help is greatly appreciated.
update:
I had the button on a UIView that was hidden on startup of the puzzle. When the user pressed the "Sounds Settings" icon, the sound setting UIView was unhidden. I had the button on this func to unhide the sound settings. I moved it to viewDidLoad() and it fixed it.
I suggest you to define a boolean variable that keeps the current state of your button. Then, you should set current image of button according to the current state of the variable.
var isSoundOn = false
#objc func soundButtonTapped(_ sender: Any) {
isSoundOn.toggle()
if isSoundOn {
// your logic when sound on (set button selected image, action etc)
} else {
// logic when sound off (set button not selected image, action etc)
}
}
If you still want to use soundButton.isSelected as your boolean variable,do not define images for different states in soundButton.setImage(yourImage, for: .selected) and soundButton.setImage(yourImage, for: .normal) and define them as follows:
soundButton.setImage(soundButton.isSelected ? soundOnImage : soundOffImage, for: .normal)
One of those two approaches above can be used.
UPDATE:
As Lloyd Kaijzer stated, isSoundOn = !isSoundOn updated as isSoundOn.toggle()

Fill button icon when button pressed in swift

I have a button with icon, I want when pressed button icon fill with color and when pressed again empty color and return to the previous state
Note: As much as possible I do not want to change icon after every pressed.
Here is example how you can achieve that, let me know if you don’t understand something.
class ViewController: UIViewController {
#IBOutlet weak var someBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
//Setting up images for normal and selected state.
func configureUI() {
let image = UIImage(named: "image")
let imageFilled = UIImage(named: "image-filled")
someBtn.setImage(image, for: .normal)
someBtn.setImage(imageFilled, for: .selected)
}
#IBAction func someBtnPressed(_ sender: Any) {
// Toggle basically makes someBtn’s selected state either true or false when pressed
someBtn.isSelected.toggle()
}
}
You can call setImage(_:for:) method to set the image of the button for a particular state.
The button is at the normal state when the user is not pressing it, so you should do:
yourButton.setImage(hollowHeart, for: .normal)
The button is at the highlighted state when the user is touching it, so you should do:
yourButton.setImage(filledHeart, for: .highlighted)
You just need to do this once after you create the button, probably in viewDidLoad.

Item user selected to be marked as a favorite to be shown on another screen

I'm working on a project where the user can see a list of restaurants, tap on one and look on further info (Master-DetailView & TabBar Application).
I really want to implement a favorite button so the user can watch all his favorites restaurants in 1 screen.
I've already made the button in the detailView :
//create a new button
let Favoritebutton: UIButton = UIButton(type: UIButtonType.Custom)
//set image for button
Favoritebutton.setImage(UIImage(named: "EmptyHeart.png"), forState: UIControlState.Normal)
Favoritebutton.setImage(UIImage(named: "FilledHeart.png"), forState: UIControlState.Selected)
//add function for button
Favoritebutton.addTarget(self, action: #selector(self.button(_:)), forControlEvents: .TouchUpInside)
//set frame
Favoritebutton.frame = CGRectMake(90, 90, 35, 35)
let barButton = UIBarButtonItem(customView: Favoritebutton)
//assign button to navigationbar
self.navigationItem.rightBarButtonItem = barButton
let defaults = NSUserDefaults.standardUserDefaults()
let buttonIsSelected = defaults.boolForKey("keyForIsButtonSelected") // If no value exists for this key then false is returned
Favoritebutton.selected = buttonIsSelected
#IBAction func button(sender: UIButton) {
sender.selected = !sender.selected
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setBool(sender.selected, forKey: "keyForIsButtonSelected")
defaults.synchronize()
Now the only missing part i have is to actually show the detailView selected as favorite to be shown on another screen (FavoritesViewController e.g)
or in another way : Item user selected to be marked as a favorite to be shown on another screen,And by that my favorite feature will be completed.
How can i show the tableViewCell the user tapped on to enter the detailView to show in another screen when the Favorite Button is selected( FavoritesViewController e.g)?
I'm using Swift 2.3 and Xcode 8,if any more info on the project is needed let me know. Thank you

How to change UIButton label programmatically

When I first run my app, I retrieve a number from my server and display it for my UIButton label. Think of this as a notification number displayed on a red UIButton.
When I remove a notification within the app, I want my UIButton label decrement by 1. I am able to get the decremented number from the server after I delete a notification, but I can't display this new number on the UIButton. The button always displays the number when the app is first fired.
I call makeButtonView() method after I remove a notification to update the UIButton
func makeButtonView(){
var button = makeButton()
view.addSubView(button)
button.tag = 2
if (view.viewWithTag(2) != nil) {
view.viewWithTag(2)?.removeFromSuperview()
var updatedButton = makeButton()
view.addSubview(updatedButton)
}else{
println("No button found with tag 2")
}
}
func makeButton() -> UIButton{
let button = UIButton(frame: CGRectMake(50, 5, 60, 40))
button.setBackgroundImage(UIImage(named: "redBubbleButton"), forState: .Normal)
API.getNotificationCount(userID) {
data, error in
button.setTitle("\(data)", forState: UIControlState.Normal)
}
button.addTarget(self, action: "targetController:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}
Use this code for Swift 4 or 5
button.setTitle("Click Me", for: .normal)
I need more information to give you a proper code. But this approach should work:
lazy var button : UIButton = {
let button = UIButton(frame: CGRectMake(50, 5, 60, 40))
button.setBackgroundImage(UIImage(named: "redBubbleButton"), forState: .Normal)
button.addTarget(self, action: "targetController:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}()
func makeButtonView(){
// This should be called just once!!
// Likely you should call this method from viewDidLoad()
self.view.addSubview(button)
}
func updateButton(){
API.getNotificationCount(userID) {
data, error in
// be sure this is call in the main thread!!
button.setTitle("\(data)", forState: UIControlState.Normal)
}
}
There have been some updates since Swift 4. This works for me:
self.button.setTitle("Button Title", for: UIControl.State.init(rawValue: 0))
Replace button with your IBOutlet name. You can also use a variable or array in place of the quoted text.
It's fairly simple ...
import UIKit
class ViewController: UIViewController {
#IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.setTitle("hello world", forState: UIControlState.Normal)
}
}
I believe if you set the state to normal, the value will propagate by default to other states so long as you haven't explicitly set a title for those states.
Said differently, if you set it for normal, it should also display this title when the button enters additional states
UIControlState.allZeros
UIControlState.Application
UIControlState.Disabled
UIControlState.Highlighted
UIControlState.Reserved
UIControlState.Selected
Lastly, here's Apple's documentation in case you have other questions.
Since your API call should be running on a background thread you need to dispatch your UI update back to the main thread like this:
DispatchQueue.main.async {
button.setTitle(“new value”, forState: .normal)
}
After setting the title, just a simple redraw of the button will do:
button.setNeedsDisplay();

Resources