He aprendido que podemos cambiar la apariencia del botón UISwitch en su estado "encendido", pero ¿también es posible cambiar el color del UISwitch en el estado "apagado"?
He aprendido que podemos cambiar la apariencia del botón UISwitch en su estado "encendido", pero ¿también es posible cambiar el color del UISwitch en el estado "apagado"?
Respuestas:
Mi solución con # swift2:
let onColor = _your_on_state_color
let offColor = _your_off_state_color
let mSwitch = UISwitch(frame: CGRectZero)
mSwitch.on = true
/*For on state*/
mSwitch.onTintColor = onColor
/*For off state*/
mSwitch.tintColor = offColor
mSwitch.layer.cornerRadius = mSwitch.frame.height / 2
mSwitch.backgroundColor = offColor
Resultado:
UISwitch
es 31pt.
Intenta usar esto
yourSwitch.backgroundColor = [UIColor whiteColor];
youSwitch.layer.cornerRadius = 16.0;
Todo gracias a @Barry Wyckoff.
CGAffineTransformMakeScale(0.80, 0.80)
. Y esto no funciona con la vista a escala. Porque la capa de la vista no cambia de tamaño. ¿Cómo puedo hacer que esto funcione?
Puede utilizar la tintColor
propiedad en el conmutador.
switch.tintColor = [UIColor redColor]; // the "off" color
switch.onTintColor = [UIColor greenColor]; // the "on" color
Tenga en cuenta que esto requiere iOS 5+
Rápido IBDesignable
import UIKit
@IBDesignable
class UISwitchCustom: UISwitch {
@IBInspectable var OffTint: UIColor? {
didSet {
self.tintColor = OffTint
self.layer.cornerRadius = 16
self.backgroundColor = OffTint
}
}
}
establecer clase en el inspector de identidad
cambiar el color del inspector de atributos
Salida
Aquí hay un truco bastante bueno: puede acceder directamente a la subvista del UISwitch que dibuja su fondo "apagado" y cambiar su color de fondo. Esto funciona mucho mejor en iOS 13 que en iOS 12:
if #available(iOS 13.0, *) {
self.sw.subviews[0].subviews[0].backgroundColor = .green
} else if #available(iOS 12.0, *) {
self.sw.subviews[0].subviews[0].subviews[0].backgroundColor = .green
}
La mejor manera de administrar el color y el tamaño de fondo de UISwitch
Por ahora es el código Swift 2.3
import Foundation
import UIKit
@IBDesignable
class UICustomSwitch : UISwitch {
@IBInspectable var OnColor : UIColor! = UIColor.blueColor()
@IBInspectable var OffColor : UIColor! = UIColor.grayColor()
@IBInspectable var Scale : CGFloat! = 1.0
override init(frame: CGRect) {
super.init(frame: frame)
self.setUpCustomUserInterface()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setUpCustomUserInterface()
}
func setUpCustomUserInterface() {
//clip the background color
self.layer.cornerRadius = 16
self.layer.masksToBounds = true
//Scale down to make it smaller in look
self.transform = CGAffineTransformMakeScale(self.Scale, self.Scale);
//add target to get user interation to update user-interface accordingly
self.addTarget(self, action: #selector(UICustomSwitch.updateUI), forControlEvents: UIControlEvents.ValueChanged)
//set onTintColor : is necessary to make it colored
self.onTintColor = self.OnColor
//setup to initial state
self.updateUI()
}
//to track programatic update
override func setOn(on: Bool, animated: Bool) {
super.setOn(on, animated: true)
updateUI()
}
//Update user-interface according to on/off state
func updateUI() {
if self.on == true {
self.backgroundColor = self.OnColor
}
else {
self.backgroundColor = self.OffColor
}
}
}
Swift 4 forma más fácil y rápida de conseguirlo en 3 pasos:
// background color is the color of the background of the switch
switchControl.backgroundColor = UIColor.white.withAlphaComponent(0.9)
// tint color is the color of the border when the switch is off, use
// clear if you want it the same as the background, or different otherwise
switchControl.tintColor = UIColor.clear
// and make sure that the background color will stay in border of the switch
switchControl.layer.cornerRadius = switchControl.bounds.height / 2
Si cambia manualmente el tamaño del interruptor (por ejemplo, usando el diseño automático), también tendrá que actualizarlo switch.layer.cornerRadius
, por ejemplo, anulando layoutSubviews
y después de llamar a super actualizando el radio de la esquina:
override func layoutSubviews() {
super.layoutSubviews()
switchControl.layer.cornerRadius = switchControl.bounds.height / 2
}
switchControl
Si necesita otros conmutadores en su aplicación, también podría ser una buena idea implementar el código de @ LongPham dentro de una clase personalizada. Como han señalado otros, para el estado "desactivado", también deberá cambiar el color de fondo, ya que el valor predeterminado es transparente.
class MySwitch: UISwitch {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Setting "on" state colour
self.onTintColor = UIColor.green
// Setting "off" state colour
self.tintColor = UIColor.red
self.layer.cornerRadius = self.frame.height / 2
self.backgroundColor = UIColor.red
}
}
El UISwitch offTintColor
es transparente, por lo que lo que está detrás del interruptor se muestra. Por lo tanto, en lugar de enmascarar el color de fondo, basta con dibujar una imagen en forma de interruptor detrás del interruptor (esta implementación asume que el interruptor está posicionado por diseño automático):
func putColor(_ color: UIColor, behindSwitch sw: UISwitch) {
guard sw.superview != nil else {return}
let onswitch = UISwitch()
onswitch.isOn = true
let r = UIGraphicsImageRenderer(bounds:sw.bounds)
let im = r.image { ctx in
onswitch.layer.render(in: ctx.cgContext)
}.withRenderingMode(.alwaysTemplate)
let iv = UIImageView(image:im)
iv.tintColor = color
sw.superview!.insertSubview(iv, belowSubview: sw)
iv.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
iv.topAnchor.constraint(equalTo: sw.topAnchor),
iv.bottomAnchor.constraint(equalTo: sw.bottomAnchor),
iv.leadingAnchor.constraint(equalTo: sw.leadingAnchor),
iv.trailingAnchor.constraint(equalTo: sw.trailingAnchor),
])
}
[Pero mira ahora mi otra respuesta .]
2020 a partir de Xcode 11.3.1 y Swift 5
Esta es la forma más sencilla que he encontrado de configurar el color de estado desactivado de UISwitch con una línea de código . Escribir esto aquí desde esta página es lo que apareció primero cuando estaba mirando y las otras respuestas no ayudaron.
Esto es si quisiera establecer el estado de apagado en rojo y se puede agregar a la función viewDidLoad ():
yourSwitchName.subviews[0].subviews[0].backgroundColor = UIColor.red
Nota: lo que realmente está haciendo es configurar el color de fondo del interruptor. Esto también puede influir en el color del interruptor en el estado de encendido (aunque para mí esto no fue un problema, ya que quería que el estado de encendido y apagado fuera del mismo color).
Una solución para esto:
Simplemente une los colores con una declaración "si más" dentro de tu IBAction. Si el interruptor está apagado, colorea el fondo de rojo. Si el interruptor está activado, deje el fondo despejado para que el color "activado" elegido se muestre correctamente.
Esto va dentro del interruptor IBAction.
if yourSwitch.isOn == false {
yourSwitch.subviews[0].subviews[0].backgroundColor = UIColor.red
} else {
yourSwitch.subviews[0].subviews[0].backgroundColor = UIColor.clear
}
Encontré un comportamiento en el que, cuando la aplicación se reanudaba desde el fondo, el fondo del interruptor volvía a borrarse. Para solucionar este problema, simplemente agregué el siguiente código para establecer el color cada vez que la aplicación pasa a primer plano:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationWillEnterForeground(_:)),
name: UIApplication.willEnterForegroundNotification,
object: nil)
}
@objc func applicationWillEnterForeground(_ notification: NSNotification) {
yourSwitch.subviews[0].subviews[0].backgroundColor = UIColor.red
yourSwitch.subviews[0].subviews[0].backgroundColor = UIColor.red
}
Parece más simple que las otras respuestas. ¡Espero que ayude!
Una forma más segura en Swift 3 sin valores mágicos de 16 puntos:
class ColoredBackgroundSwitch: UISwitch {
var offTintColor: UIColor {
get {
return backgroundColor ?? UIColor.clear
}
set {
backgroundColor = newValue
}
}
override func layoutSubviews() {
super.layoutSubviews()
let minSide = min(frame.size.height, frame.size.width)
layer.cornerRadius = ceil(minSide / 2)
}
}
XCode 11, Swift 5
No prefiero usar subViews, porque nunca se sabe cuándo Apple cambiará la jerarquía.
así que uso la vista de máscara en su lugar.
funciona con iOS 12, iOS 13
private lazy var settingSwitch: UISwitch = {
let swt: UISwitch = UISwitch()
// set border color when isOn is false
swt.tintColor = .cloudyBlueTwo
// set border color when isOn is true
swt.onTintColor = .greenishTeal
// set background color when isOn is false
swt.backgroundColor = .cloudyBlueTwo
// create a mask view to clip background over the size you expected.
let maskView = UIView(frame: swt.frame)
maskView.backgroundColor = .red
maskView.layer.cornerRadius = swt.frame.height / 2
maskView.clipsToBounds = true
swt.mask = maskView
// set the scale to your expectation, here is around height: 34, width: 21.
let scale: CGFloat = 2 / 3
swt.transform = CGAffineTransform(scaleX: scale, y: scale)
swt.addTarget(self, action: #selector(switchOnChange(_:)), for: .valueChanged)
return swt
}()
@objc
func switchOnChange(_ sender: UISwitch) {
if sender.isOn {
// set background color when isOn is true
sender.backgroundColor = .greenishTeal
} else {
// set background color when isOn is false
sender.backgroundColor = .cloudyBlueTwo
}
}
XCode 11, Swift 4.2
Comenzando con la solución de Matt, la agregué a un control IBDesignable personalizado. Hay un problema de tiempo en el que didMoveToSuperview()
se llama antes de que offTintColor
se establezca el que debe manejarse.
@IBDesignable public class UISwitchCustom: UISwitch {
var switchMask: UIImageView?
private var observers = [NSKeyValueObservation]()
@IBInspectable dynamic var offTintColor : UIColor! = UIColor.gray {
didSet {
switchMask?.tintColor = offTintColor
}
}
override init(frame: CGRect) {
super.init(frame: frame)
initializeObservers()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initializeObservers()
}
private func initializeObservers() {
observers.append(observe(\.isHidden, options: [.initial]) {(model, change) in
self.switchMask?.isHidden = self.isHidden
})
}
override public func didMoveToSuperview() {
addOffColorMask(offTintColor)
super.didMoveToSuperview()
}
private func addOffColorMask(_ color: UIColor) {
guard self.superview != nil else {return}
let onswitch = UISwitch()
onswitch.isOn = true
let r = UIGraphicsImageRenderer(bounds:self.bounds)
let im = r.image { ctx in
onswitch.layer.render(in: ctx.cgContext)
}.withRenderingMode(.alwaysTemplate)
let iv = UIImageView(image:im)
iv.tintColor = color
self.superview!.insertSubview(iv, belowSubview: self)
iv.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
iv.topAnchor.constraint(equalTo: self.topAnchor),
iv.bottomAnchor.constraint(equalTo: self.bottomAnchor),
iv.leadingAnchor.constraint(equalTo: self.leadingAnchor),
iv.trailingAnchor.constraint(equalTo: self.trailingAnchor),
])
switchMask = iv
switchMask?.isHidden = self.isHidden
}
}
categoría objetivo c para usar en cualquier UISwitch en el proyecto usando código o guión gráfico:
#import <UIKit/UIKit.h>
@interface UISwitch (SAHelper)
@property (nonatomic) IBInspectable UIColor *offTint;
@end
implementación
#import "UISwitch+SAHelper.h"
@implementation UISwitch (SAHelper)
@dynamic offTint;
- (void)setOffTint:(UIColor *)offTint {
self.tintColor = offTint; //comment this line to hide border in off state
self.layer.cornerRadius = 16;
self.backgroundColor = offTint;
}
@end
all finalmente usé transform y layer.cornerRadius también. Pero le agregué traducción para que sea el centro.
private func setSwitchSize() {
let iosSwitchSize = switchBlockAction.bounds.size
let requiredSwitchSize = ...
let transform = CGAffineTransform(a: requiredSwitchSize.width / iosSwitchSize.width, b: 0,
c: 0, d: requiredSwitchSize.height / iosSwitchSize.height,
tx: (requiredSwitchSize.width - iosSwitchSize.width) / 2.0,
ty: (requiredSwitchSize.height - iosSwitchSize.height) / 2.0)
switchBlockAction.layer.cornerRadius = iosSwitchSize.height / 2.0
switchBlockAction.transform = transform
}
Y usé backgroundColor y tintColor en el diseñador. Espero eso ayude.