Change color of UISwitch in "off" state

IphoneIosUiswitch

Iphone Problem Overview


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?

Iphone Solutions


Solution 1 - Iphone

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:

enter image description here

Solution 2 - Iphone

Try using this

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

All thanks to @Barry Wyckoff.

Solution 3 - Iphone

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+

Solution 4 - Iphone

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

enter image description here

change color from Attributes inspector

enter image description here

Output

enter image description here

Solution 5 - Iphone

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
}

Solution 6 - Iphone

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

Solution 7 - Iphone

enter image description here
enter image description here
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
    }
}

Solution 8 - Iphone

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

Solution 9 - Iphone

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

Solution 10 - Iphone

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
}

Solution 11 - Iphone

In Swift 4+:

off state:

switch.tintColor = UIColor.blue

on state:

switch.onTintColor = UIColor.red

Solution 12 - Iphone

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.]

Solution 13 - Iphone

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!

Solution 14 - Iphone

I tested on IOS 14, set background as off color and onTintColor as On and works:

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

Solution 15 - Iphone

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

Solution 16 - Iphone

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

}

Solution 17 - Iphone

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

Solution 18 - Iphone

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
    }

}

Solution 19 - Iphone

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser198725878View Question on Stackoverflow
Solution 1 - IphoneLong PhamView Answer on Stackoverflow
Solution 2 - IphoneSourabh BhardwajView Answer on Stackoverflow
Solution 3 - IphonebengoesboomView Answer on Stackoverflow
Solution 4 - IphoneAfzaal AhmadView Answer on Stackoverflow
Solution 5 - IphonemattView Answer on Stackoverflow
Solution 6 - Iphonekalpesh jetaniView Answer on Stackoverflow
Solution 7 - IphoneMaulik PatelView Answer on Stackoverflow
Solution 8 - IphoneIvanView Answer on Stackoverflow
Solution 9 - IphoneLuis Antonio Canettoli OrdoñezView Answer on Stackoverflow
Solution 10 - IphoneMilan NosáΔΎView Answer on Stackoverflow
Solution 11 - IphoneChrybView Answer on Stackoverflow
Solution 12 - IphonemattView Answer on Stackoverflow
Solution 13 - IphoneDave YView Answer on Stackoverflow
Solution 14 - IphoneGuilhermeView Answer on Stackoverflow
Solution 15 - IphoneAlexey SaechnikovView Answer on Stackoverflow
Solution 16 - IphoneTimur BernikovichView Answer on Stackoverflow
Solution 17 - Iphoneandrew54068View Answer on Stackoverflow
Solution 18 - IphoneescapedcanadianView Answer on Stackoverflow
Solution 19 - IphoneChen CohenView Answer on Stackoverflow