Can't trigger action of a UIButton after modifying its UI - swift

I create a UIButton which is displayed inside a XIB. But when I add a modification for the iPhone X display, I can't trigger the method inside its action. Here is the code below:
#IBOutlet weak var tryAgainButton: UIButton!
#IBAction func tryAgainButtonPressed(_ sender: UIButton) {
myFunction()
}
if UIDevice().userInterfaceIdiom == .phone, // Iphone X
UIScreen.main.nativeBounds.height == 2436 {
label.font = label.font.withSize(12)
contentView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.top.equalToSuperview().offset(-20)
containerView.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
contentView.backgroundColor? = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
containerView.backgroundColor? = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
label.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
helpButton.setTitleColor(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1), for: .normal)
tryAgainButton.setTitleColor(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1), for: .normal)
let underlineAttributes : [NSAttributedStringKey: Any] = [
NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue,
NSAttributedStringKey.foregroundColor : #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
]
let helpButtonAttributeString = NSMutableAttributedString(string: "Help",
attributes: underlineAttributes)
let tryAgainButtonAttributeString = NSMutableAttributedString(string: "Try Again",
attributes: underlineAttributes)
helpButton.setAttributedTitle(helpButtonAttributeString, for: .normal)
tryAgainButton.setAttributedTitle(tryAgainButtonAttributeString, for: .normal)
}
}
myFunction() is not reachable when I run with an Iphone X.

Related

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
}
}

Swift How to process multiple button UI elegantly?

In my viewController I need to process button UI
I think my approach to process UI is not efficient
What if someday I need to do more button?
Today I just happen to have only three.....
Just want user press one of three, and others keep original color
like make user feel which one they press in many button
Here's my #IBAction
#IBAction func btnPress (_ sender: UIButton) {
let clickedBackgroundColor = UIColor(red: 1, green: 153, blue: 202, a: 1)
let clickedTextColor = UIColor(red: 255, green: 255, blue: 255, a: 1)
let originBackgroundColor = UIColor(red: 216, green: 247, blue: 250, a: 1)
let originTextColor = UIColor(red: 0, green: 71, blue: 88, a: 1)
switch sender {
case btnA:
btnA.backgroundColor = clickedBackgroundColor
btnA.setTitleColor(clickedTextColor, for: .normal)
btnA.underline()
btnB.backgroundColor = originBackgroundColor
btnB.setTitleColor(originTextColor, for: .normal)
btnC.backgroundColor = originBackgroundColor
btnC.setTitleColor(originTextColor, for: .normal)
case btnB:
btnB.backgroundColor = clickedBackgroundColor
btnB.setTitleColor(clickedTextColor, for: .normal)
btnB.underline()
btnA.backgroundColor = originBackgroundColor
btnA.setTitleColor(originTextColor, for: .normal)
btnC.backgroundColor = originBackgroundColor
btnC.setTitleColor(originTextColor, for: .normal)
case btnC:
btnC.backgroundColor = clickedBackgroundColor
btnC.setTitleColor(clickedTextColor, for: .normal)
btnC.underline()
btnA.backgroundColor = originBackgroundColor
btnA.setTitleColor(originTextColor, for: .normal)
btnB.backgroundColor = originBackgroundColor
btnB.setTitleColor(originTextColor, for: .normal)
default:break
}
}
And My UIButton Extension for adding underline
I can only add underline but how to remove it if user click other button?
extension UIButton {
func underline() {
guard let text = self.titleLabel?.text else { return }
let attributedString = NSMutableAttributedString(string: text)
attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: text.count))
self.setAttributedTitle(attributedString, for: .normal)
}
}
I'm really new, not good at questioning if need more info just ask for me, Thanks.
You simply can create an Outlet Collection for all buttons instead of explicitly creating an array of buttons and use that to set the button's properties as per the selection, i.e.
#IBOutlet var buttons: [UIButton]!
Usage:
#IBAction func btnPress (_ sender: UIButton) {
let clickedBackgroundColor = UIColor(red: 1, green: 153, blue: 202, a: 1)
let clickedTextColor = UIColor(red: 255, green: 255, blue: 255, a: 1)
let originBackgroundColor = UIColor(red: 216, green: 247, blue: 250, a: 1)
let originTextColor = UIColor(red: 0, green: 71, blue: 88, a: 1)
buttons.forEach { (button) in
button.backgroundColor = (button == sender) ? clickedBackgroundColor : originBackgroundColor
button.setTitleColor((button == sender) ? clickedTextColor : originTextColor, for: .normal)
if button == sender {
button.underline()
}
}
}
Note: Also, there is no need to traverse the array twice. One single traversal will work fine.

How to Convert a string into a UIColor (Swift)

I have several colors defined in my SKScene:
let color1 = UIColor(red: 1, green: 153/255, blue: 0, alpha: 1)
let color2 = UIColor(red: 74/255, green: 134/255, blue: 232/255, alpha: 1)
let color3 = UIColor(red: 0, green: 0, blue: 1, alpha: 1)
let color4 = UIColor(red: 0, green: 1, blue: 0, alpha: 1)
let color5 = UIColor(red: 153/255, green: 0, blue: 1, alpha: 1)
let color6 = UIColor(red: 1, green: 0, blue: 0 , alpha: 1)
These colors correspond to tiles with different values in my game. The one tile goes with color1 and so on...
When the tiles are added together, I add their values and want to give them a new color according to their value.
So I want the value of the tile to play an effect on what color the tile is.
I have tried:
tile.color = UIColor(named: "color\(value)") ?? color1
But when I do this, it always uses the default value(color1).
How do I make so the value of the tile plays an effect in the color of the tile?
Named UIColors are initalized from color set in xcassets catalog.
You can set color depending on your value
switch value {
case 2: tile.color = color2
...
default: tile.color = color1
}
or you can create color sets in xcassets catalog.
UIColor named: only works when you define a color set asset. Since your colors are defined in code, UIColor named: will never return anything but nil.
One solution is to put your colors into a dictionary instead of separate variables.
let colors: [String: UIColor] = [
"color1" : UIColor(red: 1, green: 153/255, blue: 0, alpha: 1),
"color2" : UIColor(red: 74/255, green: 134/255, blue: 232/255, alpha: 1),
"color3" : UIColor(red: 0, green: 0, blue: 1, alpha: 1),
"color4" : UIColor(red: 0, green: 1, blue: 0, alpha: 1),
"color5" : UIColor(red: 153/255, green: 0, blue: 1, alpha: 1),
"color6" : UIColor(red: 1, green: 0, blue: 0 , alpha: 1),
]
Then you can get your color as:
tile.color = colors["color\(value)"] ?? colors["color1"]!

How to customize outlined button using MDCButtons in Swift?

I'm customizing my UIButton using MDCButton. I want to make my button outlined and customize its color.
In this case, I'm using MDCOutlinedButtonThemer.
I also implement MDCButton (MDCButtonColorThemer) with custom color in other button and it working.
I've tried to set my button with default MDCOutlinedButton and it works.
This is my code :
MDCOutlinedButtonThemer.applyScheme(buttonScheme, to: self.btnAddToCart)
MDCButtonColorThemer.applySemanticColorScheme(ApplicationScheme.shared.colorScheme, to: self.btnBuy)
This is the ApplicationScheme.swift :
public let colorScheme: MDCColorScheming = {
let scheme = MDCSemanticColorScheme(defaults: .material201804)
//TODO: Customize our app Colors after this line
scheme.primaryColor = UIColor(red: 255.0 / 255.0, green: 201.0 / 255.0, blue: 46.0 / 255.0, alpha: 1)
//scheme.primaryColorVariant = UIColor(red: 68.0/255.0, green: 44.0/255.0, blue: 46.0/255.0, alpha: 1.0)
//scheme.onPrimaryColor = UIColor(red: 255.0/255.0, green: 201.0/255.0, blue: 46.0/255.0, alpha: 1.0)
scheme.secondaryColor = UIColor(red: 254.0/255.0, green: 201.0/255.0, blue: 46.0/255.0, alpha: 1.0)
//scheme.onSecondaryColor = UIColor(red: 68.0/255.0, green: 44.0/255.0, blue: 46.0/255.0, alpha: 1.0)
scheme.surfaceColor = UIColor(red: 255.0/255.0, green: 201.0/255.0, blue: 46.0/255.0, alpha: 1.0)
//scheme.onSurfaceColor = UIColor(red: 255.0/255.0, green: 201.0/255.0, blue: 46.0/255.0, alpha: 1.0)
scheme.backgroundColor = UIColor(red: 255.0/255.0, green: 201.0/255.0, blue: 46.0/255.0, alpha: 1.0)
//scheme.onBackgroundColor = UIColor(red: 68.0/255.0, green: 44.0/255.0, blue: 46.0/255.0, alpha: 1.0)
//scheme.errorColor = UIColor(red: 197.0/255.0, green: 3.0/255.0, blue: 43.0/255.0, alpha: 1.0)
return scheme
}()
I want to make "Add to cart" button's border color same with "buy" button's color
You can use next color settings for creation MDCButton:
let myButton = MDCButton()
myButton.setTitle("Add to cart", for: .normal)
myButton.isUppercaseTitle = false
myButton.addTarget(self, action: #selector(myButtonAction(_:)), for: .touchUpInside)
myButton.frame = CGRect(x: 10, y: 10, width: 150, height: 40)
myButton.setBackgroundColor(UIColor.white)
myButton.setTitleColor(UIColor.blue, for: UIControl.State.normal)
myButton.setBorderColor(UIColor.lightGray, for: UIControl.State.normal)
myButton.setBorderWidth(1.0, for: UIControl.State.normal)
myButton.layer.cornerRadius = 5
view.addSubview(myButton)

Can i use 'for' loop on this?

I'm wondering if i may use 'for' loop for this code. Please forgive me, I know that is kind of a lame question, but I'm new to swift. Hope that you can help me here, guys!
Thanks a lot everyone!
Code:
override func viewDidLoad() {
super.viewDidLoad()
// Background color
let kolorTla = UIColor(red: 0/255.0, green: 66/255.0, blue: 132/255.0, alpha: 1.0)
view.backgroundColor = kolorTla
// Icons border
ramka.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
ramka.layer.cornerRadius = 5.0
ramka.layer.borderWidth = 3
// Image
skill1.image = UIImage(named: "english")
// Image border
skill1.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
skill1.layer.cornerRadius = 5.0
skill1.layer.borderWidth = 3
skill1.contentMode = .scaleAspectFit
// Image
skill2.image = UIImage(named: "literature")
// Image border
skill2.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
skill2.layer.cornerRadius = 5.0
skill2.layer.borderWidth = 3
skill2.contentMode = .scaleAspectFit
// Image
skill3.image = UIImage(named: "idea1")
// Image border
skill3.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
skill3.layer.cornerRadius = 5.0
skill3.layer.borderWidth = 3
skill3.contentMode = .scaleAspectFit
You can to some extent. You would just need to define an array of your items and loop over them. Not sure if it saves you much code wise but does make it a little more understandable.
override func viewDidLoad() {
super.viewDidLoad()
// Background color
let kolorTla = UIColor(red: 0/255.0, green: 66/255.0, blue: 132/255.0, alpha: 1.0)
view.backgroundColor = kolorTla
// Icons border
ramka.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
ramka.layer.cornerRadius = 5.0
ramka.layer.borderWidth = 3
// Set Image
skill1.image = UIImage(named: "english")
skill2.image = UIImage(named: "literature")
skill3.image = UIImage(named: "idea1")
// Set Image border
for skill in [skill1, skill2, skill3] {
skill.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
skill.layer.cornerRadius = 5.0
skill.layer.borderWidth = 3
skill.contentMode = .scaleAspectFit
}
}
Better approach at least in my opinion would be to create a simple function to handle this instead.
override func viewDidLoad() {
super.viewDidLoad()
// Background color
let kolorTla = UIColor(red: 0/255.0, green: 66/255.0, blue: 132/255.0, alpha: 1.0)
view.backgroundColor = kolorTla
// Icons border
ramka.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
ramka.layer.cornerRadius = 5.0
ramka.layer.borderWidth = 3
// Set Images
setupImageView(imageView: skill1, imageName: "english")
setupImageView(imageView: skill2, imageName: "literature")
setupImageView(imageView: skill3, imageName: "idea1")
}
func setupImageView(imageView: UIImageView, imageName: String) {
// Set Image
imageView.image = UIImage(named: imageName)
// Set Image border
imageView.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
imageView.layer.cornerRadius = 5.0
imageView.layer.borderWidth = 3
imageView.contentMode = .scaleAspectFit
}
While you're not able to use a for loop to modify the variable names and loop through them, you could put your skill instances in an array and loop through them that way.
...
skill1.image = UIImage(named: "english")
skill2.image = UIImage(named: "literature")
skill3.image = UIImage(named: "idea1")
let skills = [skill1, skill2, skill3]
for skill in skills {
skill.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
skill.layer.cornerRadius = 5.0
skill.layer.borderWidth = 3
skill.contentMode = .scaleAspectFit
}
Yes, you can. Place skill1,skill2, and skill3 in an array and iterate over it like this:
var objectArray = [skill1,skill2,skill3]
for object in objectArray
{
object.layer = ....
}
You could just extend your ImageView
extension UIImageView {
func addCustomLayer() { // add arguments to function if you wish to change the value assigned
self.layer.borderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1.0).cgColor
self.layer.cornerRadius = 5.0
self.layer.borderWidth = 3
self.contentMode = .scaleAspectFit
}
}
}
Then you call that method on each UIImageView
for each in [skill1, skill2, skill3] {
each.addCustomLayer()
}