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?
-
have you used tintColor property to change colour? – rishi Apr 27 '12 at 10:21
19 Answers
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
Result:

- 7,331
- 5
- 34
- 66

- 7,464
- 3
- 29
- 40
-
7Hey, @longpham , I would just make a little change on the radius code. In case the height ever changes I would use: mSwitch.layer.cornerRadius = mSwitch.frame.height/2 (I'm just paranoid). – Felipe Dec 11 '15 at 14:17
-
1@Felipe Gringo No problem. Depend on your UI. Standard `UISwitch` is 31pt. – Long Pham Dec 13 '15 at 13:11
Try using this
yourSwitch.backgroundColor = [UIColor whiteColor];
youSwitch.layer.cornerRadius = 16.0;
All thanks to @Barry Wyckoff.

- 2,524
- 1
- 17
- 19
-
2THIS is correct answer:) setTint changes the "outline" colour as well which visually "hides" the background on white background. – Lukasz 'Severiaan' Grela Jul 30 '14 at 10:14
-
2Be aware that the background is in rectangular shape. – Lukasz 'Severiaan' Grela Jul 31 '14 at 08:25
-
My switch is resized with `CGAffineTransformMakeScale(0.80, 0.80)`. And this is not working with scaled view. Because view's layer is not resized. How can i make this work? – AykutE Jul 10 '15 at 01:27
-
1@aykutt for scaled view you can use yourSwitch.layer.cornerRadius = yourSwitch.frame.height / 2 / scaleFactor – Hans Terje Bakke Aug 06 '19 at 18:24
You can use the tintColor
property on the switch.
switch.tintColor = [UIColor redColor]; // the "off" color
switch.onTintColor = [UIColor greenColor]; // the "on" color
Note this requires iOS 5+

- 2,119
- 2
- 23
- 27
-
4Setting tintColor in iOS7 removes "outline" for me (tint white against white background). – Lukasz 'Severiaan' Grela Jul 30 '14 at 10:05
Swift IBDesignable
import UIKit
@IBDesignable
class UISwitchCustom: UISwitch {
@IBInspectable var OffTint: UIColor? {
didSet {
self.tintColor = OffTint
self.layer.cornerRadius = 16
self.backgroundColor = OffTint
}
}
}
set class in Identity inspector
change color from Attributes inspector
Output

- 816
- 10
- 16
-
-
-
running Xcode 11.2.1, works when running the app, but it does not show the color in IB.... anyway, it works when deployed to device. – zumzum Nov 20 '19 at 22:50
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
}

- 515,959
- 87
- 875
- 1,141
-
Probably not crash during subscription in future iOS better to use subviews.first?. instead of subviews[0]. – Igor Palaguta Sep 14 '20 at 14:26
-
-
@ Igor Palaguta, here we have 2 subviews, can you please post your complete code. – Naresh Jul 07 '21 at 07:34
-
Minor issue to be aware of with this technique; for some reason, iOS likes to erase this color back to the default once the app comes back from the background. – Peter Parker Apr 21 '22 at 04:52
Working 100% IOS 13.0 and Swift 5.0 switch both state color set same #ios13 #swift #swift5
@IBOutlet weak var switchProfile: UISwitch!{
didSet{
switchProfile.onTintColor = .red
switchProfile.tintColor = .red
switchProfile.subviews[0].subviews[0].backgroundColor = .red
}
}

- 2,045
- 17
- 24
The Best way to manage background color & size of UISwitch
For now it's Swift 2.3 code
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
}
}
}

- 1,775
- 19
- 33
Swift 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
}
}

- 1,320
- 16
- 26
Should you need other switches around your app, it might be also a good idea implementing @LongPham's code inside a custom class. As others have pointed out, for the "off" state you'll need to change the background colour as well, since the default is transparent.
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
}
}

- 8,465
- 6
- 41
- 47

- 956
- 9
- 14
Swift 4 easiest and fastest way to get it in 3 steps:
// 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
If you manually change the size of the switch (e.g., by using autolayout), you will have to update the switch.layer.cornerRadius
too, e.g., by overriding layoutSubviews
and after calling super updating the corner radius:
override func layoutSubviews() {
super.layoutSubviews()
switchControl.layer.cornerRadius = switchControl.bounds.height / 2
}

- 19,169
- 4
- 55
- 90
-
what is integrationSwitch? and also, doesnt seem to work in iOS 11. Changing the background color changes a larger looking view around the switch – Just a coder May 29 '18 at 12:48
-
-
1@iOSCalendarViewOnMyProfile it's supposed to change the background color, not the bullet itself.. in iOS look and feel that's always the default color.. – Milan Nosáľ May 29 '18 at 12:50
The UISwitch offTintColor
is transparent, so whatever is behind the switch shows through. Therefore, instead of masking the background color, it suffices to draw a switch-shaped image behind the switch (this implementation assumes that the switch is positioned by autolayout):
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),
])
}
[But see now my other answer.]

- 515,959
- 87
- 875
- 1,141
In Swift 4+:
off
state:
switch.tintColor = UIColor.blue
on
state:
switch.onTintColor = UIColor.red

- 547
- 1
- 12
- 34
2020 As of Xcode 11.3.1 & Swift 5
Here's the simplest way I've found of doing setting the UISwitch off-state colour with one line of code. Writing this here since this page is what came up first when I was looking and the other answers didn't help.
This is if I wanted to set the off state to be red, and can be added to the viewDidLoad() function:
yourSwitchName.subviews[0].subviews[0].backgroundColor = UIColor.red
Note - what this is actually doing is setting the background colour of the switch. This may influence the colour of the switch in the on-state too (though for me this wasn't a problem since I wanted the on and off state to be the same colour).
A solution for this:
Simply tie in the colours with an 'if else' statement inside your IBAction. If the switch is off, colour the background red. If the switch is on, leave the background clear so your chosen 'on' colour will display properly.
This goes inside the switch IBAction.
if yourSwitch.isOn == false {
yourSwitch.subviews[0].subviews[0].backgroundColor = UIColor.red
} else {
yourSwitch.subviews[0].subviews[0].backgroundColor = UIColor.clear
}
I found some behaviour where, upon the app resuming from background, the switch background would return to clear. To remedy this problem I simply added in the following code to set the colour every time the app comes to the foreground:
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
}
Seems simpler than the other answers. Hope that helps!

- 414
- 4
- 7
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
implementation
#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

- 1,218
- 9
- 11

- 453
- 6
- 16
More safe way in Swift 3 without magical 16pt values:
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)
}
}

- 5,660
- 4
- 45
- 58
XCode 11, Swift 5
I don't prefer using subViews, cause you never know when apple gonna change the hierarchy.
so I use mask view instead.
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
}
}

- 1,326
- 14
- 29
I tested on IOS 14, set background as off color and onTintColor as On and works:
uiSwitch.onTintColor = UIColor.blue
uiSwitch.backgroundColor = UIColor.red

- 877
- 9
- 16
-
This doesn't seem to work on iOS 16. backgroundColor colors the whole switch box and omits rounded corners. As others suggested below you need to add a .layer.cornerRadius – William T. Jan 18 '23 at 17:17
-
I updated my App for IOS 16 and still working ok. no need to add nothing more on my app. – Guilherme Feb 09 '23 at 13:43
XCode 11, Swift 4.2
Starting with Matt's solution I added it to a custom, IBDesignable control. There is a timing issue in that didMoveToSuperview()
is called before the offTintColor
is set that needed to be handled.
@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
}
}

- 283
- 5
- 10
all I finally used transform and layer.cornerRadius too. But I have added translation to it to be center.
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
}
And I did use backgroundColor and tintColor in designer. Hope it helps.

- 31
- 5