Ubah warna UISwitch dalam kondisi "off"

100

Saya telah mempelajari bahwa kita dapat mengubah tampilan tombol UISwitch dalam status "on", tetapi apakah mungkin juga untuk mengubah warna UISwitch dalam status "off"?

pengguna198725878
sumber
Sudahkah Anda menggunakan properti tintColor untuk mengubah warna?
resi

Jawaban:

136

Solusi saya dengan # 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

Hasil:

masukkan deskripsi gambar di sini

Long Pham
sumber
6
Hai, @longpham, saya hanya akan membuat sedikit perubahan pada kode radius. Jika ketinggian berubah, saya akan menggunakan: mSwitch.layer.cornerRadius = mSwitch.frame.height / 2 (Saya hanya paranoid).
Felipe
@ Felipe Gringo Tidak masalah. Tergantung pada UI Anda. Standar UISwitch31pt.
Long Pham
133

Coba gunakan ini

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

Semua berkat @Barry Wyckoff.

Sourabh Bhardwaj
sumber
2
INI adalah jawaban yang benar :) setTint mengubah warna "garis besar" yang secara visual "menyembunyikan" latar belakang putih.
Lukasz 'Severiaan' Grela
2
Ketahuilah bahwa latar belakang berbentuk persegi panjang.
Lukasz 'Severiaan' Grela
Tombol saya diubah ukurannya dengan CGAffineTransformMakeScale(0.80, 0.80). Dan ini tidak berfungsi dengan tampilan berskala. Karena lapisan tampilan tidak diubah ukurannya. Bagaimana saya bisa membuat ini bekerja?
aykutt
1
@aykutt untuk tampilan berskala Anda dapat menggunakan yourSwitch.layer.cornerRadius = yourSwitch.frame.height / 2 / scaleFactor
Hans Terje Bakke
37

Anda dapat menggunakan tintColorproperti di sakelar.

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

Perhatikan bahwa ini membutuhkan iOS 5+

bengoesboom
sumber
3
Menyetel tintColor di iOS7 menghapus "garis luar" untuk saya (semburat putih dengan latar belakang putih).
Lukasz 'Severiaan' Grela
28

Swift IBDesignable

import UIKit
@IBDesignable

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

set kelas di inspektur Identitas

masukkan deskripsi gambar di sini

ubah warna dari inspektur Atribut

masukkan deskripsi gambar di sini

Keluaran

masukkan deskripsi gambar di sini

Afzaal Ahmad
sumber
Itu tidak memberikan hasil yang tepat dalam 3
Ketan P
@KetanP bisakah anda menjelaskan lebih detail?
Afzaal Ahmad
menjalankan Xcode 11.2.1, berfungsi saat menjalankan aplikasi, tetapi tidak menunjukkan warna di IB .... bagaimanapun, ini berfungsi saat diterapkan ke perangkat.
zumzum
12

Berikut adalah trik yang cukup bagus: Anda bisa langsung menuju subview UISwitch yang menarik background "off", dan mengubah warna background. Ini bekerja jauh lebih baik di iOS 13 daripada di 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
}
Matt
sumber
Mungkin tidak crash selama berlangganan di iOS masa depan lebih baik menggunakan subviews.first ?. bukan subview [0].
Igor Palaguta
@IgorPalaguta Ya, ide bagus. Saya akan membuat perubahan itu.
matt
6

Cara terbaik untuk mengelola warna & ukuran latar belakang UISwitch

Untuk saat ini kode 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
        }
    }
}
kalpesh jetani
sumber
5

Di Swift 4+:

off negara:

switch.tintColor = UIColor.blue

on negara:

switch.onTintColor = UIColor.red
Chryb
sumber
3
Ini tidak berfungsi di iOS 13+, pengaturan tintColortidak berpengaruh.
Eric
5

Cepat 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
    }
}
Ivan
sumber
4

Swift 4 cara termudah dan tercepat untuk mendapatkannya dalam 3 langkah:

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

Jika Anda mengubah ukuran sakelar secara manual (misalnya, dengan menggunakan autolayout), Anda juga harus memperbarui switch.layer.cornerRadius, misalnya, dengan mengganti layoutSubviewsdan setelah memanggil super, memperbarui radius sudut:

override func layoutSubviews() {
    super.layoutSubviews()
    switchControl.layer.cornerRadius = switchControl.bounds.height / 2
}
Milan Nosáľ
sumber
apa itu integrationSwitch? dan juga, sepertinya tidak berfungsi di iOS 11. Mengubah warna latar belakang mengubah tampilan yang lebih besar di sekitar sakelar
FlowUI. SimpleUITesting.com
@iOSCalendarViewOnMyProfile maaf, seharusnyaswitchControl
Milan Nosáľ
1
@iOSCalendarViewOnMyProfile seharusnya mengubah warna latar belakang, bukan peluru itu sendiri .. di iOS tampilan dan nuansa yang selalu menjadi warna default ..
Milan Nosáľ
4

Jika Anda memerlukan sakelar lain di sekitar aplikasi Anda, mungkin ada baiknya juga menerapkan kode @ LongPham di dalam kelas khusus. Seperti yang ditunjukkan orang lain, untuk status "off", Anda juga perlu mengubah warna latar belakang, karena defaultnya transparan.

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
  }
}
Luis Antonio Canettoli
sumber
3

UISwitch offTintColortransparan, jadi apa pun yang ada di belakang sakelar akan terlihat. Oleh karena itu, alih-alih menutupi warna latar belakang, cukup menggambar gambar berbentuk sakelar di belakang sakelar (implementasi ini mengasumsikan bahwa sakelar diposisikan oleh 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),
    ])
}

[Tapi lihat sekarang jawaban saya yang lain .]

Matt
sumber
2

2020 Sejak Xcode 11.3.1 & Swift 5

Inilah cara paling sederhana yang saya temukan untuk melakukan pengaturan UISwitch off-state color dengan satu baris kode . Menulis ini di sini karena halaman ini adalah yang muncul pertama kali ketika saya melihat dan jawaban lainnya tidak membantu.

Ini jika saya ingin menyetel status nonaktif menjadi merah, dan dapat ditambahkan ke fungsi viewDidLoad ():

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

Catatan - apa yang sebenarnya dilakukan adalah menyetel warna latar belakang sakelar. Ini dapat mempengaruhi warna sakelar dalam keadaan hidup juga (meskipun bagi saya ini bukan masalah karena saya ingin keadaan hidup dan mati memiliki warna yang sama).

Solusi untuk ini:

Cukup ikat warna dengan pernyataan 'jika lagi' di dalam IBAction Anda. Jika sakelar mati, warnai latar belakang dengan merah. Jika sakelar aktif, biarkan latar belakang bersih sehingga warna 'aktif' yang Anda pilih akan ditampilkan dengan benar.

Ini masuk ke dalam saklar IBAction.

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

Saya menemukan beberapa perilaku di mana, setelah aplikasi melanjutkan dari latar belakang, latar belakang sakelar akan kembali menjadi jelas. Untuk memperbaiki masalah ini saya hanya menambahkan kode berikut untuk mengatur warna setiap kali aplikasi datang ke latar depan:

 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
}

Tampak lebih sederhana dari jawaban lainnya. Semoga membantu!

Dave Y
sumber
Jawaban yang indah dan sederhana, terima kasih banyak, +1
mAc
1

Cara yang lebih aman di Swift 3 tanpa nilai 16pt magis:

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

}
Timur Bernikovich
sumber
1

XCode 11, Swift 5

Saya tidak lebih suka menggunakan subView, karena Anda tidak pernah tahu kapan apple akan mengubah hierarki.

jadi saya menggunakan tampilan topeng sebagai gantinya.

ini bekerja dengan 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
sumber
1

masukkan deskripsi gambar di sini
masukkan deskripsi gambar di sini
Bekerja 100% IOS 13.0 dan Swift 5.0 beralih kedua warna negara disetel sama # ios13 #swift # swift5

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

XCode 11, Swift 4.2.0

Dimulai dengan solusi Matt, saya menambahkannya ke kontrol IBD yang dapat dirancang khusus. Ada masalah waktu yang didMoveToSuperview()dipanggil sebelum offTintColorset yang perlu ditangani.

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

}
escapedcanadian
sumber
0

kategori obyektif c untuk digunakan pada setiap UISwitch dalam proyek menggunakan kode atau storyboard:

#import <UIKit/UIKit.h>

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

penerapan

#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
Alexey Saechnikov
sumber
0

semua saya akhirnya menggunakan transform dan layer.cornerRadius juga. Tetapi saya telah menambahkan terjemahan untuk menjadi pusat.

    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
}

Dan saya menggunakan backgroundColor dan tintColor di desainer. Semoga membantu.

Chen Cohen
sumber