简体   繁体   中英

How do I set UIButton background color forState: UIControlState.Highlighted in Swift

I can set the background color for a button but I can't work out how to set the background color for UIControlState.Highlighted . Is it even possible? or do I need to go down the setBackgroundImage path?

If anyone stops by, another way to go maybe more easily if it is something you need more than once... I wrote a short extension for UIButton, it works just fine:

for Swift 3

extension UIButton {
    func setBackgroundColor(color: UIColor, forState: UIControlState) {
        UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
        CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), color.CGColor)
        CGContextFillRect(UIGraphicsGetCurrentContext(), CGRect(x: 0, y: 0, width: 1, height: 1))
        let colorImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        self.setBackgroundImage(colorImage, forState: forState)
    }
}

for Swift 4

extension UIButton {
    func setBackgroundColor(color: UIColor, forState: UIControl.State) {
        self.clipsToBounds = true  // add this to maintain corner radius
        UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
        if let context = UIGraphicsGetCurrentContext() {
            context.setFillColor(color.cgColor)
            context.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
            let colorImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            self.setBackgroundImage(colorImage, for: forState)
        }
    }
}

You use it just like setBackgroundImage :

yourButton.setBackgroundColor(color: UIColor.white, forState: UIControl.State.highlighted)

Syntax changes to @winterized extension for Swift 3+ syntax

extension UIButton {
    func setBackgroundColor(color: UIColor, forState: UIControlState) {
        UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
        UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor)
        UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
        let colorImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.setBackgroundImage(colorImage, for: forState)
    }}

Below will be one way to go. Two IBActions. One to control background color when depressing a button, one on release.

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var button: UIButton!

    @IBAction func buttonClicked(sender: AnyObject) { //Touch Up Inside action
        button.backgroundColor = UIColor.whiteColor()
    }

    @IBAction func buttonReleased(sender: AnyObject) { //Touch Down action
        button.backgroundColor = UIColor.blueColor()

    }

    override func viewDidLoad() {
        super.viewDidLoad()

    }
}

When you look at the autocomplete options for your button after adding a period, you can set a background color, but not for specified state. You can only set background images. Now of course if you are married to doing it this way instead of using the method I show above, you could load an image of the desired color as the background image using the setbackgroundImageForState property.

在此处输入图片说明

在此处输入图片说明

Swift 4+ compatibility for the accepted answer :

extension UIButton {

  /// Sets the background color to use for the specified button state.
  func setBackgroundColor(color: UIColor, forState: UIControlState) {

    let minimumSize: CGSize = CGSize(width: 1.0, height: 1.0)

    UIGraphicsBeginImageContext(minimumSize)

    if let context = UIGraphicsGetCurrentContext() {
      context.setFillColor(color.cgColor)
      context.fill(CGRect(origin: .zero, size: minimumSize))
    }

    let colorImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    self.clipsToBounds = true
    self.setBackgroundImage(colorImage, for: forState)
  }
}

Compatible SwiftLint and fix the bug of broken auto layout / corner radius.

Swift 4 Version of this solution :

extension UIButton {

    func setBackgroundColor(_ color: UIColor, for state: UIControlState) {

        UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
        UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor)
        UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
        let colorImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        setBackgroundImage(colorImage, for: state)
    }
}

Seems nobody here has mentioned using Key Value Observation yet, but it's another approach.

A reason for doing so instead of picking the other answers here is you don't need to go creating new images all the time nor be concerned with secondary effects of assigning images to buttons (eg cornerRadius effects).

But you'll need to create a class for the observer, who would be responsible for storing the different background colours and applying them in the observeValue() method.

public class ButtonHighlighterObserver: NSObject {

  var observedButton:UIButton? = nil

  var backgroundColor: UIColor            = UIColor.white
  var backgroundHighlightColor: UIColor   = UIColor.gray

  public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

    // Perform background color changes when highlight state change is observed
    if keyPath == "highlighted", object as? UIButton === observedButton {
        observedButton!.backgroundColor = observedButton!.isHighlighted ? self.backgroundHighlightColor : self.backgroundColor
    }
}

}

Then all you need to do is manage addObserver / removeObserver during operation:

// Add observer to button's highlighted value
button.addObserver(anObserver, forKeyPath: "highlighted", options: [.new], context: nil)
anObserver.observedButton = button

// ...

// And at deinit time, be sure you remove the observer again
anObserver.observedButton?.removeObserver(item, forKeyPath: "highlighted")
anObserver.observedButton = nil

Update Swift 4

 extension UIButton {

    func setBackgroundColor(color: UIColor, forState: UIControlState) {

        UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
        UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor)
        UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
        let colorImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()


        self.setBackgroundImage(colorImage, for: forState)
    }

Event Button Action

Show Touch On Hightlight

Why not?

@implementation UIButton (Color)

- (void) setBackgroundColor:(UIColor*)color forState:(UIControlState)state
{
    [self setBackgroundImage:[UIImage.alloc initWithCIImage:[CIImage imageWithColor:[CIColor colorWithCGColor:color.CGColor]]] forState:state];
}

@end

I can set the background color for a button but I can't work out how to set the background color for UIControlState.Highlighted . Is it even possible? or do I need to go down the setBackgroundImage path?

in Swift 5

For those who don't want to use colored background to beat the selected state

Simply you can beat the problem by using #Selector & if statement to change the UIButton colors for each state individually easily

For Example:

    override func viewDidLoad() {
    super.viewDidLoad()
    //to reset the button color to its original color ( optionally )
    self.myButtonOutlet.backgroundColor = UIColor.white  
}

@IBOutlet weak var myButtonOutlet: UIButton!{
    didSet{  // Button selector and image here
        self.myButtonOutlet.setImage(UIImage(systemName: ""), for: UIControl.State.normal)

        self.myButtonOutlet.setImage(UIImage(systemName: "checkmark"), for: UIControl.State.selected)



        self.myButtonOutlet.addTarget(self, action: #selector(tappedButton), for: UIControl.Event.touchUpInside)
    }
}

@objc func tappedButton() {  // Colors selection is here
    if self.myButtonOutlet.isSelected == true {

        self.myButtonOutlet.isSelected = false
        self.myButtonOutlet.backgroundColor = UIColor.white         
    } else {
        self.myButtonOutlet.isSelected = true

        self.myButtonOutlet.backgroundColor = UIColor.black
        self.myButtonOutlet.tintColor00 = UIColor.white

    }
}

You can override isHighlighted and changed the background color when the isHighlighted is set.

Example: TextButton.Swift

import UIKit

class TextButton: UIButton {

   private var text: String = "Submit" {
       didSet{
           setText()
       }
   }

   var hightlightedColor : UIColor = UIColor(red: 50/255, green: 50/255, blue: 50/255, alpha: 1)

   var background :UIColor = .black {
       didSet{
           self.backgroundColor = background
       }
   }

   override var isHighlighted: Bool {
       didSet {
           self.backgroundColor = self.isHighlighted ? hightlightedColor : background
       }
   }

   // MARK: - Lifecycle
   override init(frame: CGRect) {
       super.init(frame: frame)
       sharedLayout()
   }

   required init?(coder aDecoder: NSCoder) {
       super.init(coder: aDecoder)
       sharedLayout()
   }



   // MARK: - Method
   private func setText() {
       self.setTitle(text, for: .normal)
   }

   private func sharedLayout() {
       self.setTitle(text, for: .normal)
       self.backgroundColor = self.isHighlighted ? .green : background
       self.layer.cornerRadius = 8
   }

}

Usages:

let nextBtn = TextButton()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM