Change color of UISwitch in "off" state

I've learned that we can change the UISwitch button appearance in its "on" state, but is it also possible to change the color of the UISwitch in the "off" state?

83865 次浏览

You can use the tintColor property on the switch.

switch.tintColor = [UIColor redColor]; // the "off" color
switch.onTintColor = [UIColor greenColor]; // the "on" color

注意,这需要 iOS5 +

用这个试试

yourSwitch.backgroundColor = [UIColor whiteColor];
youSwitch.layer.cornerRadius = 16.0;

感谢@Barry Wyckoff。

My solution with #swift2:

let onColor  = _your_on_state_color
let offColor = _your_off_state_color


let mSwitch = UISwitch(frame: CGRect.zero)
mSwitch.on = true


/*For on state*/
mSwitch.onTintColor = onColor


/*For off state*/
mSwitch.tintColor = offColor
mSwitch.layer.cornerRadius = mSwitch.frame.height / 2.0
mSwitch.backgroundColor = offColor
mSwitch.clipsToBounds = true

结果:

enter image description here

斯威夫特 IBDesignable

import UIKit
@IBDesignable


class UISwitchCustom: UISwitch {
@IBInspectable var OffTint: UIColor? {
didSet {
self.tintColor = OffTint
self.layer.cornerRadius = 16
self.backgroundColor = OffTint
}
}
}

在身份检查器中设置类

enter image description here

change color from Attributes inspector

enter image description here

输出

enter image description here

objective c category to use on any UISwitch in project using code or storyboard:

#import <UIKit/UIKit.h>


@interface UISwitch (SAHelper)
@property (nonatomic) IBInspectable UIColor *offTint;
@end

实施

#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

管理 UISswitch 背景颜色和大小的最佳方法

现在是 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 3没有神奇的16pt 值:

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


}

最简单、最快速的方法是:

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

如果你手动改变开关的大小(例如,使用自动布局) ,你将不得不更新 switch.layer.cornerRadius,例如,覆盖 layoutSubviews和调用超级更新角的半径:

override func layoutSubviews() {
super.layoutSubviews()
switchControl.layer.cornerRadius = switchControl.bounds.height / 2
}

UISswitch offTintColor是透明的,所以在开关后面的任何东西都可以显示出来。因此,与其屏蔽背景颜色,不如画一个开关形状的图像 后面开关(这个实现假设开关是通过自动布局定位的) :

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),
])
}

[但现在看看我的 另一个答案。]

在 Swift 4 + :

off州:

switch.tintColor = UIColor.blue

on州:

switch.onTintColor = UIColor.red

XCode 11,Swift 4.2

Matt 的解决方案开始,我将它添加到一个自定义 IBDesignable 控件中。在设置需要处理的 offTintColor之前调用 didMoveToSuperview()是一个时间问题。

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


}

迅捷5:

import UIKit


extension UISwitch {


func set(offTint color: UIColor ) {
let minSide = min(bounds.size.height, bounds.size.width)
layer.cornerRadius = minSide / 2
backgroundColor = color
tintColor = color
}
}

如果您需要在应用程序周围安装其他开关,那么在自定义类中实现@LongPham 的代码可能也是一个好主意。 正如其他人指出的那样,对于“关闭”状态,你还需要改变背景颜色,因为默认颜色是透明的。

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

Here's a pretty good trick: you can just reach right into the UISwitch's subview that draws its "off" background, and change its background color. This works a lot better in iOS 13 than it does in iOS 12:

if #available(iOS 13.0, *) {
self.sw.subviews.first?.subviews.first?.backgroundColor = .green
} else if #available(iOS 12.0, *) {
self.sw.subviews.first?.subviews.first?.subviews.first?.backgroundColor = .green
}

2020年 Xcode 11.3.1 & Swift 5

这是我发现的用 一行代码设置 UISswitch 非状态颜色的最简单方法。写这里,因为这一页是什么出现在第一时间,当我正在寻找和其他答案没有帮助。

这是如果我想将 off 状态设置为红色,并且可以添加到 viewDidLoad ()函数:

yourSwitchName.subviews[0].subviews[0].backgroundColor = UIColor.red

注意-这实际上是在设置开关的背景颜色。这也可能影响开关在开启状态下的颜色(虽然对我来说这不是一个问题,因为我希望开关状态是相同的颜色)。

解决方案:

只需在你的 IBAction 中用一个“ if else”语句将颜色结合起来即可。如果开关关闭,将背景涂成红色。如果开关是打开的,留下背景 安全,这样你选择的“打开”颜色就会正确显示。

This goes 在里面 the switch IBAction.

  if yourSwitch.isOn == false {
yourSwitch.subviews[0].subviews[0].backgroundColor = UIColor.red
} else {
yourSwitch.subviews[0].subviews[0].backgroundColor = UIColor.clear
}

我发现了一些行为,当应用程序从后台恢复时,开关背景将恢复为清晰。为了解决这个问题,我简单地添加了以下代码,以便在每次应用程序出现在前台时设置颜色:

 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
}

看起来比其他答案简单,希望能有帮助!

XCode 11 Swift 5

我不喜欢使用子视图,因为你永远不知道苹果什么时候会改变层次结构。

所以我用蒙版视图代替。

it works with 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
}
}


所有我最后使用变换和图层。角半径也。 但我加了翻译,使它成为中心。

    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
}

我确实在设计中使用了背景色和色彩。 希望能有帮助。

enter image description here
enter image description here
工作100% IOS 13.0和 Swift 5.0开关两个状态颜色设置相同 # ios13 # Swift # Swift 5

@IBOutlet weak var switchProfile: UISwitch!{
didSet{
switchProfile.onTintColor = .red
switchProfile.tintColor = .red
switchProfile.subviews[0].subviews[0].backgroundColor = .red
}
}

我在 IOS 14上进行了测试,将背景设置为关闭颜色,将 onTintColor 设置为开启并运行:

uiSwitch.onTintColor = UIColor.blue
uiSwitch.backgroundColor = UIColor.red