Изменить цвет переключателя UISwitch в выключенном состоянии

100

Я узнал, что мы можем изменить внешний вид кнопки UISwitch в состоянии «включено», но можно ли также изменить цвет кнопки UISwitch в состоянии «выключено»?

user198725878
источник
вы использовали свойство tintColor для изменения цвета?
риши

Ответы:

136

Мое решение с # 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

Результат:

введите описание изображения здесь

Лонг Фам
источник
6
Привет, @longpham, я бы немного изменил код радиуса. Если высота когда-либо изменится, я бы использовал: mSwitch.layer.cornerRadius = mSwitch.frame.height / 2 (я просто параноик).
Фелипе
@ Фелипе Гринго Нет проблем. Зависит от вашего пользовательского интерфейса. Стандарт UISwitch- 31 пункт.
Лонг Фам
133

Попробуйте использовать это

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

Все благодаря @Barry Wyckoff.

Сураб Бхардвадж
источник
2
ЭТО правильный ответ :) setTint также изменяет цвет «контура», который визуально «скрывает» фон на белом фоне.
Лукаш 'Severiaan' Грела
2
Имейте в виду, что фон имеет прямоугольную форму.
Лукаш 'Severiaan' Грела
Размер моего переключателя изменен с помощью CGAffineTransformMakeScale(0.80, 0.80). И это не работает с масштабированным видом. Поскольку размер слоя представления не изменяется. Как я могу заставить это работать?
aykutt
1
@aykutt для масштабированного просмотра вы можете использовать yourSwitch.layer.cornerRadius = yourSwitch.frame.height / 2 / scaleFactor
Hans Terje Bakke
37

Вы можете использовать tintColorсвойство на переключателе.

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

Обратите внимание, для этого требуется iOS 5+.

Bengoesboom
источник
3
Установка tintColor в iOS7 удаляет для меня «контур» (оттенок белого на белом фоне).
Лукаш 'Severiaan' Грела
28

Swift IB

import UIKit
@IBDesignable

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

установить класс в инспекторе удостоверений

введите описание изображения здесь

изменить цвет из инспектора атрибутов

введите описание изображения здесь

Вывод

введите описание изображения здесь

Афзал Ахмад
источник
Это не выдаёт должный результат в быстром 3
Ketan P
@KetanP, можете ли вы подробнее объяснить проблему?
Афзал Ахмад
под управлением Xcode 11.2.1, работает при запуске приложения, но не показывает цвет в IB .... в любом случае, он работает при развертывании на устройстве.
zumzum
12

Вот довольно хороший трюк: вы можете просто войти прямо в подпредставление UISwitch, которое рисует свой «выключенный» фон, и изменить его цвет. В iOS 13 это работает намного лучше, чем в 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
}
матовый
источник
Наверное, не вылетит во время подписки, в будущем iOS лучше использовать subviews.first ?. вместо subviews [0].
Игорь Палагута
@IgorPalaguta Да, хорошая идея. Я внесу это изменение.
матовый
6

Лучший способ управлять цветом и размером фона UISwitch

Пока это код 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
        }
    }
}
Кальпеш Джетани
источник
5

В Swift 4+:

off штат:

switch.tintColor = UIColor.blue

on штат:

switch.onTintColor = UIColor.red
Chryb
источник
3
Это не работает на iOS 13+, настройка tintColorне влияет.
Эрик
5

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
    }
}
Иван
источник
4

Swift 4 - самый простой и быстрый способ получить его за 3 шага:

// 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
}
Милан Носань
источник
что такое IntegrationSwitch? а также, похоже, не работает в iOS 11. Изменение цвета фона меняет более крупный вид вокруг переключателя
FlowUI. SimpleUITesting.com
@iOSCalendarViewOnMyProfile, извините, так и должно бытьswitchControl
Милан Ношань
1
@iOSCalendarViewOnMyProfile он должен изменить цвет фона, а не саму пулю .. в стиле iOS это всегда цвет по умолчанию ..
Милан Ноша
4

Если вам нужны другие переключатели в вашем приложении, также может быть хорошей идеей реализовать код @ 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
  }
}
Луис Антонио Канеттоли
источник
3

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

[Но посмотрим теперь мой другой ответ .]

матовый
источник
2

2020 Начиная с Xcode 11.3.1 и Swift 5

Вот самый простой способ, который я нашел, установить цвет выключенного состояния UISwitch с помощью одной строчки кода . Пишу это здесь, потому что эта страница - это то, что появилось первым, когда я искал, и другие ответы не помогли.

Это если я хотел установить состояние выключения красным, и его можно добавить в функцию viewDidLoad ():

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

Обратите внимание: на самом деле это установка цвета фона переключателя. Это также может повлиять на цвет переключателя во включенном состоянии (хотя для меня это не было проблемой, поскольку я хотел, чтобы состояние включения и выключения было одного цвета).

Решение для этого:

Просто свяжите цвета с помощью оператора if else внутри вашего IBAction. Если переключатель выключен, закрасьте фон красным цветом. Если переключатель включен, оставьте фон чистым, чтобы выбранный вами цвет «включен» отображался правильно.

Это происходит внутри переключателя 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
}

Кажется проще, чем другие ответы. Надеюсь, это поможет!

Дэйв Y
источник
Красивый и простой ответ, большое спасибо, +1
mAc
1

Более безопасный способ в 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)
  }

}
Тимур Берникович
источник
1

XCode 11, Swift 5

Я не предпочитаю использовать subView, потому что никогда не знаешь, когда Apple изменит иерархию.

поэтому вместо этого я использую маску.

работает с 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
        }
    }
andrew54068
источник
1

введите описание изображения здесь
введите описание изображения здесь
При работе 100% IOS 13.0 и Swift 5.0 оба цвета переключаются одинаково # ios13 #swift # swift5

@IBOutlet weak var switchProfile: UISwitch!{
    didSet{
        switchProfile.onTintColor = .red
        switchProfile.tintColor = .red
        switchProfile.subviews[0].subviews[0].backgroundColor = .red
    }
}
Маулик Патель
источник
0

XCode 11, Swift 4.2

Начиная с решения Мэтта, я добавил его в пользовательский элемент управления IBDesignable. Существует проблема синхронизации, которая didMoveToSuperview()вызывается перед offTintColorустановкой, которую необходимо обработать.

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

}
сбежалканадец
источник
0

Категория цели c для использования в любом UISwitch в проекте с использованием кода или раскадровки:

#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
Алексей Саечников
источник
0

В конце концов, я тоже использовал transform и layer.cornerRadius. Но я добавил к нему перевод, чтобы он был по центру.

    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
}

И я использовал backgroundColor и tintColor в дизайнере. Надеюсь, поможет.

Чен Коэн
источник