Как установить цвет фона UIButton для State: UIControlState.Highlighted в Swift
Я могу установить цвет фона для кнопки, но не могу понять, как установить цвет фона для UIControlState.Highlighted
, Это вообще возможно? или мне нужно идти вниз setBackgroundImage
дорожка?
13 ответов
Если кто-то зайдет, другой путь, возможно, будет проще, если вам нужно что-то более одного раза... Я написал небольшое расширение для UIButton, оно работает просто отлично:
для 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)
}
}
для 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)
}
}
}
Вы используете это так же, как setBackgroundImage
:
yourButton.setBackgroundColor(UIColor.whiteColor(), forState: UIControlState.Highlighted)
Изменения синтаксиса в расширении @winterized для синтаксиса Swift 3+
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)
}}
Ниже будет один путь. Два IBActions. Один для управления цветом фона при нажатии кнопки, другой при отпускании.
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()
}
}
Когда вы смотрите на опции автозаполнения для вашей кнопки после добавления периода, вы можете установить цвет фона, но не для указанного состояния. Вы можете установить только фоновые изображения. Теперь, конечно, если вы женаты на том, чтобы делать это таким образом, вместо того, чтобы использовать метод, который я показал выше, вы можете загрузить изображение нужного цвета в качестве фонового изображения, используя свойство setbackgroundImageForState.
Совместимость Swift 4+ для принятого ответа:
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)
}
}
Совместим SwiftLint и исправим ошибку с разбитым авто макетом / радиусом угла.
Swift 4 версия этого решения:
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)
}
}
Обновление 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)
}
Событие Кнопка Действие
Показать Touch On Hightlight
Кажется, никто здесь не упомянул об использовании Key Value Observation, но это другой подход.
Причина, по которой вместо того, чтобы выбирать другие ответы, заключается в том, что вам не нужно постоянно создавать новые изображения и не беспокоиться о вторичных эффектах назначения изображений кнопкам (например, эффектах cornerRadius).
Но вам нужно создать класс для наблюдателя, который будет отвечать за хранение различных цветов фона и их применение в observeValue()
метод.
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
}
}
}
Тогда все, что вам нужно сделать, это управлять addObserver / removeObserver во время работы:
// 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
Вы можете переопределить и изменить цвет фона, когда
isHighlighted
установлен.
Пример: 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
}
}
Использование:
let nextBtn = TextButton()
Почему бы и нет?
@implementation UIButton (Color)
- (void) setBackgroundColor:(UIColor*)color forState:(UIControlState)state
{
[self setBackgroundImage:[UIImage.alloc initWithCIImage:[CIImage imageWithColor:[CIColor colorWithCGColor:color.CGColor]]] forState:state];
}
@end
Можем ли мы сделать то же самое, используя атрибуты времени выполнения?
@IBInspectable var HighlightedBackground: Bool {
get {
return true
}
set {
layer.backgroundColor = Common.sharedInstance.OrangeColor.CGColor
print("highlighted state")
}
}
В Swift 5
Для тех, кто не хочет использовать цветной фон для победы над выбранным состоянием
Просто вы можете решить проблему, используя оператор #Selector & if, чтобы легко изменить цвета UIButton для каждого состояния индивидуально.
Например:
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
}
}
Свифт 5
В моем случае мне нужно было что-то еще, потому что вариант с расширением и функцией setBackgroundColor не работает должным образом в случае, когда у нас разные цвета фона кнопок для темного/светлого режима и когда мы меняем traitCollection.userInterfaceStyle (темный/светлый режим). Поэтому я использовал пользовательскую реализациюUIButton
класс и переопределить свойстваisHighlighted
иisEnabled
:
import UIKit
class CustomButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.isEnabled = isEnabled
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var isHighlighted: Bool {
didSet {
self.backgroundColor = isHighlighted ? UIColor.blue : UIColor.cyan
}
}
override var isEnabled: Bool {
didSet {
self.backgroundColor = isEnabled ? UIColor.cyan : UIColor.red
}
}
}
Если вы используете раскадровку или xib, используйте
@IBInspectable
добавив расширение для
UIButton
import Foundation
import UIKit
import ObjectiveC
// Declare a global var to produce a unique address as the assoc object handle
var highlightedColorHandle: UInt8 = 0
extension UIButton {
func setBackgroundColor(_ color: UIColor, for state: UIControl.State) {
self.setBackgroundImage(UIImage.init(color: color), for: state)
}
@IBInspectable
var highlightedBackground: UIColor? {
get {
if let color = objc_getAssociatedObject(self, &highlightedColorHandle) as? UIColor {
return color
}
return nil
}
set {
if let color = newValue {
self.setBackgroundColor(color, for: .highlighted)
objc_setAssociatedObject(self, &highlightedColorHandle, color, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
} else {
self.setBackgroundImage(nil, for: .highlighted)
objc_setAssociatedObject(self, &highlightedColorHandle, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}
Используйте в раскадровке или Xib как