Dynamically / Programmatically assign IBAction to a button - ios

For my project, I have created an ordering menu that programmatically creates buttons that scroll horizontally. However I am looking for ways to assign IBAction - specially action to write to Firebase database - to those buttons dynamically...
Would tagging the buttons and using conditionals work?
My codes are
Food.swift - properties sets of each menu item
class Food
{
var title = ""
var featuredImage: UIImage
var color: UIColor
init(title: String, featuredImage: UIImage, color: UIColor)
{
self.title = title
self.featuredImage = featuredImage
self.color = color
}
static func fetchFoods() -> [Food]
{
return [
Food(title: " Biscuits", featuredImage: UIImage(named: "f1")!, color: UIColor(red: 63/255.0, green: 71/255.0, blue: 80/255.0, alpha: 0.6)),
Food(title: " Sandwich", featuredImage: UIImage(named: "f2")!, color: UIColor(red: 63/255.0, green: 71/255.0, blue: 80/255.0, alpha: 0.6)),
Food(title: " Veg Sandwich", featuredImage: UIImage(named: "f3")!, color: UIColor(red: 63/255.0, green: 71/255.0, blue: 80/255.0, alpha: 0.6)),
]
}
}
UICollectionCell swift
import UIKit
class FoodCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var featuredImageView: UIImageView!
#IBOutlet weak var backgroundColorView: UIView!
#IBOutlet weak var foodButton: UIButton!
var food: Food? {
didSet {
self.updateUI()
}
}
private func updateUI()
{
if let food = food {
featuredImageView.image = food.featuredImage
backgroundColorView.backgroundColor = food.color
foodButton.setTitle("\(food.title)", for: .normal)
} else {
featuredImageView.image = nil
backgroundColorView.backgroundColor = nil
foodButton.setTitle("", for: .normal)
}
}
}
Can I add to Food.swift,
var buttonTag = ""
then assign tag to individual button.
At UICollectionCell.swift, append tag. Using If...else... conditionals to match tag to individual IBAction {ref?.child...")
Thanks everyone!!!
ps.There is another swift file for arranging the menu items horizontally..

Tags are one way to do it, but the easiest way is probably to call addTarget(_:action:for:) on each one to set up its action, e.g.
button.addTarget(button,
action: #selector(buttonFunctionThatDoesSomething:),
for: .touchUpInside) // or .primaryActionTriggered
The first argument is the object whose selector (the second argument) is to be called. The #selector() syntax is really picky; you may want to read this SO answer to figure out the right way to call it.

from the apple document https://developer.apple.com/library/archive/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ImplementingACustomControl.html. :
button.addTarget(self, action: #selector(funcName), for: .touchUpInside)
and then:
#objc func funcName() {
//do what u want in here
}

Related

How can I implement Presets savings in Tableview

I need help I have these ColorSlider App that change the color of Square with 3 sliders RGB .I like to create a Tableview where i can store presets of color and retrieve from preset name e.g. Ocean Blue,
Emerald Green, Red Ferrary etc. I create The Tableview with the push of the button but I am stuck with the rest of implementation. Please I need help.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var redSlider: UISlider!
#IBOutlet weak var greenSlider: UISlider!
#IBOutlet weak var blueSlider: UISlider!
#IBOutlet weak var displaylbl: UILabel!
#IBOutlet weak var displayView: UIView!
var color:Color!
override func viewDidLoad() {
super.viewDidLoad()
color = Color(red: redSlider.value, green: greenSlider.value, blue: blueSlider.value)
displaylbl.text = color.getString()
displayView.backgroundColor = color.getColor()
}
#IBAction func sliderChanged(_ sender: UISlider) {
if (sender.tag == 1){
color.setRed(red: sender.value)
displaylbl.text = color.getString()
displayView.backgroundColor = color.getColor()
}
else if (sender.tag == 2) {
color.setGreen(green: sender.value)
displaylbl.text = color.getString()
displayView.backgroundColor = color.getColor()
}
else if (sender.tag == 3) {
color.setBlue(blue: sender.value)
displaylbl.text = color.getString()
displayView.backgroundColor = color.getColor()
}
}
}
import UIKit
class Color {
private var red:CGFloat
private var green:CGFloat
private var blue:CGFloat
init(red:Float, green:Float, blue:Float) {
self.red = CGFloat(red)
self.green = CGFloat(green)
self.blue = CGFloat(blue)
}
func setRed(red:Float) {
self.red = CGFloat(red)
}
func setGreen(green:Float) {
self.green = CGFloat(green)
}
func setBlue(blue:Float) {
self.blue = CGFloat(blue)
}
func getColor() -> UIColor {
let color = UIColor(red: red/255, green: green/255, blue: blue/255, alpha: 1.0)
return color
}
func getString() -> String {
let string = "Red: \(Int(round(red)))\nGreen: \(Int(round(green)))\nBlue: \(Int(round(blue)))"
return string
}
}
First you need to get the RGB color from slider and show in box, if you have done this part then now you need to do is whenever you are showing color in box you just make a dictionary with keys like :
let dict = [ colorName : "whatever you want",
colorCode : "Which you get from slider"
]
Add it in array too like:
arrayColor.append(dic)
Populate your tableview from arrayColor array, and in didselectatindexpath you need to get colorCode atIndexPath.row and set in box.
Hope this will help you. For any other query comment below.

Cannot use variables inside class [duplicate]

This question already has answers here:
How to initialize properties that depend on each other
(4 answers)
Closed 3 years ago.
I'm trying to follow along CS 193P course and I'm currently on a Lecture 2. The lector made var game = Concentration(numberOfPairsOfCards: cardButtons.count / 2) and it worked fine for him, however, it doesn't work at all for me. Am I missing something? I can't pass anything there.
Here's my ViewController class:
class ViewController: UIViewController {
#IBOutlet weak var flipCountLabel: UILabel!
#IBOutlet var cardButtons: [UIButton]!
var game = Concentration(numberOfPairsOfCards: cardButtons.count / 2)
var emojiChoices = ["πŸŽƒ", "πŸ‘»", "πŸŽƒ", "πŸ‘»"]
var flipCount = 0 {
didSet {
flipCountLabel.text = "Flips: \(flipCount)"
}
}
//MARK: - IBActions
#IBAction func touchCard(_ sender: UIButton) {
flipCount += 1
if let cardNumber = cardButtons.index(of: sender) {
flipCard(withEmoji: emojiChoices[cardNumber], on: sender)
}
}
//MARK: - Methods
func flipCard(withEmoji emoji: String, on button: UIButton) {
if button.currentTitle == emoji {
button.setTitle("", for: .normal)
button.backgroundColor = #colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1)
} else {
button.setTitle(emoji, for: .normal)
button.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
}
}
}
And Concentration:
class Concentration {
var cards = [Card]()
func chooseCard(at index: Int) {
}
init(numberOfPairsOfCards: Int) {
for _ in 1...numberOfPairsOfCards {
let card = Card()
cards += [card, card]
}
//TODO: - Shuffle the cards
}
}
The error is
Cannot use instance member 'cardButtons' within property initializer;
property initializers run before 'self' is available
and auto completion doesn't work either
You need to make it a var
var game:Concentration!
then inside viewDidLoad
game = Concentration(numberOfPairsOfCards: cardButtons.count / 2)
OR make it a lazy var
lazy var game:Concentration = {
return Concentration(numberOfPairsOfCards:self.cardButtons.count / 2)
}()

How to avoid button tint color change when presenting a popover in iOS?

I have a button that show a popover over fullscreen, the main view has a 6 custom views that have 5 button with a tint color in grey or blue, depending of some parameter. but when the popover appears al the button inside the customs view become gray, as soon that popover disappear the custom view get is tint color, I want to avoid that when the popover is presented the button tint conlor does not change.
the custom view is a view inside a UITableviewCell. the custom view is define as this.
class ratingDoors: UIView {
var rating: Int = 0{
didSet{
makeRating()
}
}
#IBOutlet var contentView: UIView!
#IBOutlet weak var button1: UIButton!
#IBOutlet weak var button2: UIButton!
#IBOutlet weak var button3: UIButton!
#IBOutlet weak var button4: UIButton!
#IBOutlet weak var button5: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
//fatalError("init(coder:) has not been implemented")
}
private func commonInit() {
//TODO: Do some stuff
// 1. Load the nib
Bundle.main.loadNibNamed("ratingDoors", owner: self, options: nil)
// 2. Add the 'contentView' to self
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleHeight,.flexibleWidth]
}
#IBAction func setRating(sender: UIButton){
rating = sender.tag
//makeRating()
}
func makeRating() {
button1.configureRatingButton(i: rating)
button2.configureRatingButton(i: rating)
button3.configureRatingButton(i: rating)
button4.configureRatingButton(i: rating)
button5.configureRatingButton(i: rating)
}
}
extension UIButton{
func configureRatingButton(i: Int){
if self.tag <= i {
self.tintColor = UIColor(red: 90/255, green: 212/255, blue: 227/255, alpha: 1.0)
}else{
self.tintColor = UIColor(red: 204/255, green: 204/255, blue: 204/255, alpha: 1)
}
}
}
in the tableview i have this setup for the cell
let cell = tableView.dequeueReusableCell(withIdentifier: "ratingCell") as! ratingTableViewCell
cell.ratingLabel.text = "Ordenado"
if let ordered = requestManager.instance.user.ordered{
cell.ratingView.rating = ordered
}
return cell
and so for the all 6 rows with the same view.
here is the prepare(for:)
let popoverVC = segue.destination as! popoverViewController
popoverVC.delegate = self
popoverVC.modalPresentationStyle = UIModalPresentationStyle.popover
popoverVC.popoverPresentationController!.delegate = self
the initial configuration for tview is like this.
Here is the view with the popover presented.
so how avoid the tint color change in the popover presntation?
If you set each button’s tintAdjustmentMode to .normal, they will not adjust their tint upon presenting the popover. Another option could be to use a Custom button type (instead of System) that doesn’t respond to tint changes.

IBOutletCollection collection

I'm looking for a way to change background color only for buttons that have the same text. So I created (at this time only 2) IBOutletCollections and 1 IBAction to test. But I have 27 different button numbers to code... or do I need to create 27 Outlet Collections and 27 Actions?
class SecondViewController: UIViewController {
#IBOutlet var button1color: [UIButton]!
#IBOutlet var button2color: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func bouton1(_ sender: UIButton) {
for button in self.button1color {
if button.backgroundColor == nil {
button.backgroundColor = UIColor(displayP3Red: 1, green: 1, blue: 0.5, alpha: 0.8)
} else {
button.backgroundColor = nil
}
}
}
Is there a way to create a function to avoid typing 27 times the same code for each case?
For more informations, feel free to ask me!
Thank you for your help.
I'm looking for a way to change background color only for buttons that have the same text
I understand it like this: You need collection of buttons and when some button from this collection is pressed, you want to change color for all buttons from collection which have the same text (title when we're speaking about UIButton)
So you can have just one collection for all buttons. Link them to this collection
#IBOutlet var buttons: [UIButton]!
and also you can have just one action for all buttons. Also link them to this action. Then when button is pressed, change backgroundColor of button which has the same title as button which's been pressed
#IBAction func buttonPressed(_ sender: UIButton) {
for button in buttons where button.currentTitle == sender.currentTitle {
button.backgroundColor = UIColor(displayP3Red: 1, green: 1, blue: 0.5, alpha: 0.8)
}
}

Having trouble using lazy with a var in swift

I am following the standford ios class for Fall 2017. As the professor goes through the demo, I follow by inputting and running like he does. He shows how using lazy with a var allows one to use the UIButton count for variable initialization. When I add the lazy keyword, the error doesn't go away. Thinking it was maybe an xcode update related problem, I downloaded someone else's version of the project and that project doesn't have the issue. The code is below, any thoughts? :/
class ViewController: UIViewController {
lazy var game = ConcentrationModel(numberOfPairsOfCards: (cardButtons.count + 1) / 2)
//Could have had var flipCount: Int = 0
//But it is inferred
var flipCount = 0 {
didSet {
flipCountLabel.text = "Flips: \(flipCount)"
}
}
var emojiChoices = ["πŸŽƒ","πŸ‘»","πŸ‘Ώ","πŸŽƒ","πŸ‘»","πŸ‘Ώ"]
#IBOutlet var cardButtons: [UIButton]!
#IBOutlet weak var flipCountLabel: UILabel!
#IBAction func touchCard(_ sender: UIButton) {
flipCount += 1
if let cardNumber = cardButtons.index(of: sender) {
flipCard(withEmoji: emojiChoices[cardNumber], on: sender)
print("cardNumber = \(cardNumber)")
} else {
print("chosen card was not in cardButtons")
}
print("agh!!! a ghost")
}
func flipCard(withEmoji emoji: String, on button: UIButton) {
if button.currentTitle == emoji {
button.setTitle("", for: UIControlState.normal)
button.backgroundColor = #colorLiteral(red: 1, green: 0.5763723254, blue: 0, alpha: 1)
} else {
button.setTitle(emoji, for: UIControlState.normal)
button.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
}
}
}
To initialize a lazy property which depends on the value of another property you have to use the closure syntax
lazy var game : ConcentrationModel = {
return ConcentrationModel(numberOfPairsOfCards: (self.cardButtons.count + 1) / 2)
}()

Resources