Search code examples
iosswiftxcodeuibuttonuicolor

How do I change the color of two UIButtons when I press them?


I am trying to use two buttons to toggle between an animated sliding view. When the UIView loads, I want button1 to be UIColor.darkGrey and button2 to be UIColor.lightGrey. Then, when I press button2 I want button2 to become UIColor.darkGrey and button1 to become UIColor.lightGrey. If I press button1, I want button1 to be UIColor.darkGrey and button2 to be UIColor.lightGrey.

It seems simple; Using the storyboard, I connected a UIButton for button1 and button2 as an outlet. Then I connected each as actions. In each of the actions, I included the following code:

@IBAction func button1Action(_ sender: UIButton) {
    button2.titleLabel?.textColor = UIColor.lightGray
    button1.titleLabel?.textColor = UIColor.darkGray
    UIView.animate(withDuration: 1){
        self.side1.constant = 0
        self.side2.constant = 0
        self.sideA.constant = 400
        self.sideB.constant = -400
        self.view.layoutIfNeeded()
    }
}
@IBAction func button2Action(_ sender: UIButton) {
    button1.titleLabel?.textColor = UIColor.lightGray
    button2.titleLabel?.textColor = UIColor.darkGray
    view.layoutIfNeeded()
    UIView.animate(withDuration: 1){
        self.side1.constant = -400
        self.side2.constant = 400
        self.sideA.constant = 0
        self.sideB.constant = 0
        self.view.layoutIfNeeded()
    }


}

When I press button1, everything works as expected; However, whenever I press button2 both buttons are UIColor.lightGrey. Am I missing something obvious?


Solution

  • You get some methods "for free" with buttons to manage their state. One of them is isSelected. Another is the tag property, so you can figure out which button is which. Since you've only got two buttons, you can get away with just using isSelected to figure out which is which. You can also use computed vars to make your life easier. With those things in mind, here's one approach you could utilize to managing the buttons' states:

    1. Declare a buttons computed var, like so

      @IBOutlet var firstButton: UIButton!
      @IBOutlet var secondButton: UIButton!
      
      // computed var to access your buttons
      private var buttons: [UIButton] {
          return [firstButton, secondButton]
      }
      
    2. Set up your buttons in viewDidLoad.

      override func viewDidLoad() {
          super.viewDidLoad()
      
          // one setup to configure each button for selected or not selected
          buttons.forEach { button in
              button.setTitleColor(.darkGray,
                                    for: .selected)
              button.setTitleColor(.lightGray,
                                    for: .normal)
          }
      
          firstButton.isSelected = true
      }
      

    func setTitleColor(_ color: UIColor?, for state: UIControl.State) will remain in effect for the lifetime of the button, so you don't need to fiddle with it after the initial declaration (unless you want to change the button's behavior later).

    1. One @IBAction for both buttons and utilize the tag property to figure out which one is which. Since you've only got two buttons, I'm just using isSelected. Here's what your single @IBAction would look like:

      @IBAction func buttonAction(_ sender: UIButton) {
      
          UIView.animate(withDuration: 1.0) {
              // flip buttons
              self.buttons.forEach { button in
                  button.isSelected.toggle()
              }
      
              if self.firstButton.isSelected {
                  // tweak your constraints for firstButton.isSelected == true
                  // tweak your constraints for secondButton.isSelected == false
              } else {
                  // tweak your constraints for firstButton.isSelected == false
                  // tweak your constraints for secondButton.isSelected == true
              }
      
          }
      }
      

    Based on your current implementation, you'll need to right click on the UIButtons on storyboard and nuke the existing IBAction connections and reconnect both buttons to the method above.