Swift : change style of a button when pressed and reset other buttons - swift

So I've got these buttons (3 stacks of 6, so 18), and what I want to achieve is when I press one of these buttons :
border color & text color changes
the other buttons are reset to their normal styling
But I don't want to disable the others via a "isEnabled" trick (I've only found solutions here involving isEnabled), I still want them to be enabled, I just want them not to be "highlighted" with my custom styling when one is pressed.
for the first part which is just the styling I did this inside the IBAction :
#IBAction func preset1Pressed(_ sender: UIButton) {
preset1.layer.borderColor = #colorLiteral(red: 0.4095217415, green: 0.6107917746, blue: 0.2774988226, alpha: 1)
preset1.layer.borderWidth = 0.42
preset1.setTitleColor(#colorLiteral(red: 0.4095217415, green: 0.6107917746, blue: 0.2774988226, alpha: 1), for: .normal)
}
This small portion was just for 1 button, but I guess if I have 18 of them I should make a class or a struct rather than copy this inside each IBAction ?? Or a func ?
Then for the 2nd part I'm not sure about how to do it, reversing to the original properties (set in the Attributes Inspector) of the other buttons when one is pressed.
Intuitively I'm sure it's a combination of an array of all the 18 buttons inside a function that would loop through all the array, and maybe make a bool on each button to check if they are pressed or not, but I really don't know how the syntax would be...
Worth noting also that if I press twice on the same button I don't want it to reverse to its original properties but to keep the "pressed" styling.
Thanks in advance !

Define UIButton array and add buttons when you add it to stack.set index as button tag (0-17)
fileprivate var btnArray:[UIButton] = []
btn0.tag = 0
btnArray.appent(btn0)
Then you can change style in button click function like this
#IBAction func preset1Pressed(_ sender: UIButton) {
btnArray.forEach { (button) in
if button.tag == sender.tag {
preset1.layer.borderColor = #colorLiteral(red: 0.4095217415, green: 0.6107917746, blue: 0.2774988226, alpha: 1)
preset1.layer.borderWidth = 0.42
preset1.setTitleColor(#colorLiteral(red: 0.4095217415, green: 0.6107917746, blue: 0.2774988226, alpha: 1), for: .normal)
view.layoutIfNeeded()
}else{
//add default style
view.layoutIfNeeded()
}
}
}
Don't frogot to add view.layoutIfNeeded() after this

So what suggested Dilan did not completely solve it on its own, though I experimented with it and it actually helped me solve it, apart I did these modifications :
I created my Array of buttons (called presetsArray) and tagged them.
Then I created a function to be called in all IBActions, but as sender.tag wouldn't work here's how I worked out the function :
func styleButtons(tag: Int) {
let tag = tag
presetsArray.forEach{ (button) in
if button.tag == tag {
button.layer.borderColor = #colorLiteral(red: 0.4095217415, green: 0.6107917746, blue: 0.2774988226, alpha: 1)
button.layer.borderWidth = 0.42
button.setTitleColor(#colorLiteral(red: 0.4095217415, green: 0.6107917746, blue: 0.2774988226, alpha: 1), for: .normal)
view.layoutIfNeeded()
} else {
button.layer.borderColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
button.setTitleColor(#colorLiteral(red: 0.4978774786, green: 0.5020093918, blue: 0.5019439459, alpha: 1), for: .normal)
}
}
}
Then in each IBAction for preset X I would call it like this :
styleButtons(tag: presetX.tag)
In the else section of my function as view.layoutIfNeeded() wouldn't reverse back to my original styling I just went for the color picker and picked my original styling, not the most legit way to do this I feel but it works !
Thanks a lot Dilan for the help.

Related

Swift - Problem handeling button selection

I have a floating button in my app that display 5 different buttons. Each of them has a color but initially are gray. When the user selects one of the buttons, all of them hide, and when the user taps again on the floating button, the button that was previously tapped is not gray but with its proper color.
Also the logic would be that the user can tap another one of the buttons to select it, and the previous one would be unselected, as if the user taps on a selected button, it gets unselected.
I'm using cocoa pods for the Floating Button, JJFloatingActionButton, but on the documentation there is no info about this.
func configureActionButton() {
actionButton.overlayView.backgroundColor = UIColor(white: 0, alpha: 0.5)
actionButton.buttonImage = UIImage(systemName: "line.horizontal.3.decrease")
actionButton.buttonColor = UIColor(named: "signoColor")!
actionButton.buttonImageColor = .white
actionButton.buttonImageSize = CGSize(width: 30, height: 30)
actionButton.itemAnimationConfiguration = .slideIn(withInterItemSpacing: 14)
actionButton.itemSizeRatio = CGFloat(0.75)
let item = actionButton.addItem()
item.titleLabel.text = "Button 1"
item.buttonColor = UIColor(red: 254/255.0, green: 224/255.0, blue: 255/255.0, alpha: 1.0)
item.buttonImageColor = UIColor(red: 200/255.0, green: 73/255.0, blue: 203/255.0, alpha: 1.0)
item.imageSize = CGSize(width: 30, height: 30)
item.action = { item in
//This is for the functionality of the button
}
let item2 = actionButton.addItem()
item2.titleLabel.text = "Button 2"
item2.buttonColor = UIColor(red: 254/255.0, green: 224/255.0, blue: 255/255.0, alpha: 1.0)
item2.buttonImageColor = UIColor(red: 200/255.0, green: 73/255.0, blue: 203/255.0, alpha: 1.0)
item2.imageSize = CGSize(width: 30, height: 30)
item2.action = { item in
//This is for the functionality of the button
}
//And I have 3 more buttons
}
This is how the floating button looks like:
I would appreciate some help. I've searched for similar questions but none of them solved this problem. Thank you!

The tag system for the question isn't working as the exchange change only occurs on the last button

Button Method
#objc func buttonFuction(){
let stacView = UIStackView()
stacView.spacing = 12
stacView.distribution = .fillEqually
stacView.axis = .horizontal
stacView.translatesAutoresizingMaskIntoConstraints = false
view!.addSubview(stacView)
buttonNames = ["One","Two","Three","Four"]
for i in 0..<buttonNames.count{
index+=i
button = Button()
button.setTitle(buttonNames[i], for: .normal)
stacView.addArrangedSubview(button)
buttons.append(button)
button.tag = index
button.addTarget(self, action: selectors[i], for: .touchUpInside)
button.addTarget(self, action: selectorsColor[i], for: .touchDown)
}
NSLayoutConstraint.activate([stacView.centerXAnchor.constraint(equalTo: view!.centerXAnchor),stacView.centerYAnchor.constraint(equalTo: view!.centerYAnchor),stacView.widthAnchor.constraint(equalToConstant: 350),stacView.heightAnchor.constraint(equalToConstant:70)])
}
Button handler methods
#objc func colorButton1(){
if button.tag == 0 {
button.backgroundColor = #colorLiteral(red: 0.1123025946, green: 1, blue: 0.03079073749, alpha: 1)
}
else {
button.backgroundColor = #colorLiteral(red: 0.7974829231, green: 0.09321228972, blue: 0.09321228972, alpha: 1)
}
}
#objc func colorButton2(){
if button.tag == 1 {
button.backgroundColor = #colorLiteral(red: 0.07117979832, green: 0.8973241221, blue: 0, alpha: 1)
}
else {
button.backgroundColor = #colorLiteral(red: 0.7312681945, green: 0.1133923198, blue: 0.06002510149, alpha: 1)
}
}
#objc func colorButton3(){
if button.tag == 2 {
button.backgroundColor = #colorLiteral(red: 0.1123025946, green: 1, blue: 0.03079073749, alpha: 1)
}
else {
button.backgroundColor = #colorLiteral(red: 0.6805654408, green: 0.1003367522, blue: 0.09689761347, alpha: 1)
}
}
#objc func colorButton4(){
if button.tag == 3 {
button.backgroundColor = #colorLiteral(red: 0.1123025946, green: 1, blue: 0.03079073749, alpha: 1)
}
else {
button.backgroundColor = #colorLiteral(red: 0.7620294414, green: 0.05229266211, blue: 0.09308676813, alpha: 1)
}
}
Every time I press the button it keeps changing colour to the last button, even after tagging each button, the colour change only occurs in the last button and not sure how to change the code to allow the colour change to happen on other button when pressed.
Thank you in advance.
As I said in the comments, the buttons array contains 4 items which all point – due to reference semantics – to the same instance, the lastly added Button instance. So does also the button property.
You need something like this, it creates four different Button instances and uses one action method, I don't know what the second selector does so I commented it out.
The logic: The sender parameter is the just tapped button, first set all background colors except the current button to their appropriate red colors, then set the background color of the current button to the green color. The references to the buttons are taken from the buttons array.
for i in 0..<buttonNames.count{
let button = Button()
button.setTitle(buttonNames[i], for: .normal)
stacView.addArrangedSubview(button)
buttons.append(button)
button.tag = i
button.addTarget(self, action: #selector(colorButton), for: .touchUpInside)
// button.addTarget(self, action: selectorsColor[i], for: .touchDown)
}
#objc func colorButton(_ sender : Button) {
let offColors = [#colorLiteral(red: 0.7974829231, green: 0.09321228972, blue: 0.09321228972, alpha: 1),
#colorLiteral(red: 0.7312681945, green: 0.1133923198, blue: 0.06002510149, alpha: 1),
#colorLiteral(red: 0.6805654408, green: 0.1003367522, blue: 0.09689761347, alpha: 1),
#colorLiteral(red: 0.7620294414, green: 0.05229266211, blue: 0.09308676813, alpha: 1)]
for i in 0..<4 where i != sender.tag {
buttons[i].backgroundColor = offColors[i]
}
switch sender.tag {
case 0: sender.backgroundColor = #colorLiteral(red: 0.1123025946, green: 1, blue: 0.03079073749, alpha: 1)
case 1: sender.backgroundColor = #colorLiteral(red: 0.07117979832, green: 0.8973241221, blue: 0, alpha: 1)
case 2: sender.backgroundColor = #colorLiteral(red: 0.1123025946, green: 1, blue: 0.03079073749, alpha: 1)
case 3: sender.backgroundColor = #colorLiteral(red: 0.1123025946, green: 1, blue: 0.03079073749, alpha: 1)
default: break
}
}

Why are my buttons not changing color when selected?

I have several buttons on a single view controller which I want to change color when they are selected. My current code is as follows
#IBAction func academicButtonPressed(_ sender: Any) {
if academicButton.backgroundColor == UIColor.systemBackground {
academicButton.backgroundColor = UIColor(red: 20, green: 215, blue: 201, alpha: 1)
academicButton.setTitleColor(UIColor.systemBackground, for: .selected)
} else {
academicButton.backgroundColor = UIColor.systemBackground
academicButton.setTitleColor(UIColor(red: 20, green: 115, blue: 201, alpha: 1), for: .selected)
}
}
But it doesn't work. What am I doing wrong? (This is just on of the many buttons; they will all do the same thing when selected).
I think you are doing the color comparison wrong.
Try this;
academicButton.backgroundColor.isEqual(UIColor.systemBackground)

Issues creating toggle button

I am trying to create a button that reads "Special 1" then when it is clicked, the button reads "USED" and it stays as "USED" and doesn't allow the reader to toggle it back.
For example, the Twitter "follow" button can be pressed and then the button is changed to "following". However on Twitter, the user can click the "following" button and it will change back to "follow".
For my app, I want the user to be able to click "Special 1" and then the button is changed to "USED" and it remains that way forever.
Below is the attached code that I have created so far. The problem with my code so far is that the button doesn't read "Special 1" or "USED" when it is selected, the only thing it contains is the colors. The colors change how I want them to, but I can't get the words to appear and change.
import UIKit
class SpecialOneBTN: UIButton {
var isOn = false
override init(frame: CGRect) {
super.init(frame: frame)
initButton()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initButton()
}
func initButton() {
layer.borderWidth = 2.0
layer.cornerRadius = frame.size.height/2
setTitleColor(UIColor(red: 255.0/255.0, green: 193.0/255.0, blue: 95.0/255.0, alpha: 1.0), for: .normal)
addTarget(self, action: #selector(SpecialOneBTN.buttonPressed), for: .touchUpInside )
}
#objc func buttonPressed() {
activateButton(bool: !isOn)
}
func activateButton(bool: Bool) {
isOn = bool
let color = bool ? UIColor(red: 102.0/255.0, green: 102.0/255.0, blue: 100.0/255.0, alpha: 1.0) : UIColor(red: 255.0/255.0, green: 193.0/255.0, blue: 95.0/255.0, alpha: 1.0)
let titleColor = bool ? UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0) : UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
let title = bool ? "USED" : "Special 1"
setTitle(title, for: .normal)
setTitleColor(titleColor, for: .normal)
backgroundColor = color
}
}

Using IBAction button to cycle two different sets of instructions upon multiple presses

I'm new to coding and have been attempting to put myself through an intensive course in swift. Right now I'm working on a project that I would like to have a IBAction button that completes "set 1" of instructions on first press, then "set 2" of instructions on second press. Then, press 3 would revert back to "set 1" instructions, press 4 "set 2" and so forth.
Forgive me if this is elementary, but any help would be appreciated.
//Set 1 instructions with the IBAction would be
#IBAction func punchInButtonPressed(sender: AnyObject) {
statusLabel.text = "Status: Punched In"
statusLabel.backgroundColor = UIColor(red: 96/255.0, green: 191/255.0, blue: 111/255.0, alpha: 1.0)
//Set 2 instructions would be
statusLabel.text = "Status: Punched Out"
statusLabel.backgroundColor = UIColor(red: 255/255.0, green: 110/255.0, blue: 115/255.0, alpha: 1.0)
You can handle this by adding a variable to your class that will hold the "state" of the button - punched in or punched out. Then, when the button is pressed, you toggle the state and then display the correct message:
class MyViewController: UIViewController {
var punchedIn = false
// rest of declarations
#IBAction func punchInButtonPressed(sender: AnyObject) {
// toggle status
punchedIn = !punchedIn
// show correct message
if punchedIn {
// set 1
statusLabel.text = "Status: Punched In"
statusLabel.backgroundColor = UIColor(red: 96/255.0, green: 191/255.0, blue: 111/255.0, alpha: 1.0)
} else {
// set 2
statusLabel.text = "Status: Punched Out"
statusLabel.backgroundColor = UIColor(red: 255/255.0, green: 110/255.0, blue: 115/255.0, alpha: 1.0)
}
}
}