¿Cómo crear botones de radio y casillas de verificación en swift (iOS)?

82

Estoy desarrollando una aplicación que permite realizar encuestas. Mi diseño se genera a partir de preguntas basadas en XML.

Necesito crear botones de opción (opción única) y casillas de verificación (respuestas múltiples). No encontré nada útil para Swift.

¿Alguien tiene alguna idea?

Vannian
fuente
5
Necesita crear varios botones con imagen de fondo como imagen de CheckBox o imagen de botón de radio ... al hacer clic en el botón, cambiar la imagen como imagen seleccionada ... debe tener dos conjuntos de imágenes, es decir. uno está seleccionado, otro para no seleccionado ..
RJV Kumar
2
Dado que Xcode / iOS no proporciona casilla de verificación / botón de radio, yo también uso lo que sugirió RJV.
Bista
sí, lo probé, está funcionando.
Vannian
¿Intentó utilizar las bibliotecas Cocoapods para casillas de verificación y botones de opción?
Wimukthi Rajapaksha

Respuestas:

37

Para los botones de opción y las casillas de verificación, no hay nada integrado.

Puede implementar Checkboxes fácilmente usted mismo. Puede establecer una imagen sin marcar para su botón para UIControlStateNormal y una imagen marcada para su UIControlStateSelected. Ahora con un toque, el botón cambiará su imagen y alternará entre imagen marcada y no marcada.

Para usar botones de opción, debe mantener un Arraypara todos los botones que desea que se comporten como botones de opción. Siempre que se presiona un botón, debe desmarcar todos los demás botones de la matriz.

Para los botones de radio, puede usar SSRadioButtonsController Puede crear un objeto de controlador y agregarle una matriz de botones como

var radioButtonController = SSRadioButtonsController()
radioButtonController.setButtonsArray([button1!,button2!,button3!])

El principio principal es algo como esto aquí .

Shamas S
fuente
149

Caja

Puede crear su propio control CheckBox ampliando UIButton con Swift:

import UIKit

class CheckBox: UIButton {
    // Images
    let checkedImage = UIImage(named: "ic_check_box")! as UIImage
    let uncheckedImage = UIImage(named: "ic_check_box_outline_blank")! as UIImage
    
    // Bool property
    var isChecked: Bool = false {
        didSet {
            if isChecked == true {
                self.setImage(checkedImage, for: UIControl.State.normal)
            } else {
                self.setImage(uncheckedImage, for: UIControl.State.normal)
            }
        }
    }
        
    override func awakeFromNib() {
        self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
        self.isChecked = false
    }
        
    @objc func buttonClicked(sender: UIButton) {
        if sender == self {
            isChecked = !isChecked
        }
    }
}

Y luego agréguelo a sus vistas con Interface Builder:

ingrese la descripción de la imagen aquí

Botones de radio

Los botones de radio se pueden resolver de manera similar.

Por ejemplo, la clásica selección de género Mujer - Hombre :

ingrese la descripción de la imagen aquí

import UIKit

class RadioButton: UIButton {
    var alternateButton:Array<RadioButton>?
    
    override func awakeFromNib() {
        self.layer.cornerRadius = 5
        self.layer.borderWidth = 2.0
        self.layer.masksToBounds = true
    }
    
    func unselectAlternateButtons() {
        if alternateButton != nil {
            self.isSelected = true
            
            for aButton:RadioButton in alternateButton! {
                aButton.isSelected = false
            }
        } else {
            toggleButton()
        }
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        unselectAlternateButtons()
        super.touchesBegan(touches, with: event)
    }
    
    func toggleButton() {
        self.isSelected = !isSelected
    }
    
    override var isSelected: Bool {
        didSet {
            if isSelected {
                self.layer.borderColor = Color.turquoise.cgColor
            } else {
                self.layer.borderColor = Color.grey_99.cgColor
            }
        }
    }
}

Puede iniciar sus botones de radio de esta manera:

    override func awakeFromNib() {
        self.view.layoutIfNeeded()
        
        womanRadioButton.selected = true
        manRadioButton.selected = false
    }
    
    override func viewDidLoad() {
        womanRadioButton?.alternateButton = [manRadioButton!]
        manRadioButton?.alternateButton = [womanRadioButton!]
    }

Espero eso ayude.

crubio
fuente
1
para Swift 3, debe cambiar el método buttonClicked a func buttonClicked (_ remitente: UIButton)
hilzj
1
en la primera ejecución no puedo ver ninguna imagen con mi casilla de verificación ... solo aparece después de hacer clic ... por favor ayúdenme
H Raval
2
Hola @Nitesh, puede obtener el estado Checked usando la propiedad public bool isChecked, por ejemplo: if myCheckbox.isChecked {...}
crubio
1
@ Jerland2 No tengo idea de por qué sin ver tu código. El booleano isChecked está conectado a la imagen, por lo que debe haber algo más.
crubio
1
@amorenew si todavía está buscando cómo mostrar en el generador de interfaces, consulte mi respuesta.
Mahendra Liya
22

Echa un vistazo a DLRadioButton . Puede agregar y personalizar botones de opción directamente desde Interface Builder. También funciona Swiftperfectamente.

Botón de radio Swift para iOS

Actualización: la versión 1.3.2agregó botones cuadrados, también mejoró el rendimiento.

Actualización: versión 1.4.4agregada opción de selección múltiple, también se puede usar como casilla de verificación.

Actualización: versión 1.4.7agregada soporte de idioma RTL.

David Liu
fuente
¿No veo cómo usar su botón como casilla de verificación? ¿Solo tiene botón de radio?
dleviathan
1
Para usarlo como casilla de verificación, puede configurar multipleSelectionEnabledy iconSquarepara YES.
David Liu
1
Hola @DavidLiu, estoy teniendo dificultades para implementar tu biblioteca en Swift 1.2. Soy muy nuevo en las aplicaciones de iOS, ¿su ReadMe.md se salta algunos pasos básicos? ¡Estoy muy confundido!
Milap
1
@milap ¿Puede enviar un problema y publicar un código de muestra?
David Liu
@DavidLiu Lo hice funcionar, solo necesitaba agregar su marco a los binarios integrados. ¡Quizás desee agregar ese paso para los súper principiantes!
Milap
10

Swift 5, casilla de verificación con animación

Crea una salida del botón

@IBOutlet weak var checkBoxOutlet:UIButton!{
        didSet{
            checkBoxOutlet.setImage(UIImage(named:"unchecked"), for: .normal)
            checkBoxOutlet.setImage(UIImage(named:"checked"), for: .selected)
        }
    }

Crea una extensión de UIButton

extension UIButton {
    //MARK:- Animate check mark
    func checkboxAnimation(closure: @escaping () -> Void){
        guard let image = self.imageView else {return}
        
        UIView.animate(withDuration: 0.1, delay: 0.1, options: .curveLinear, animations: {
            image.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
            
        }) { (success) in
            UIView.animate(withDuration: 0.1, delay: 0, options: .curveLinear, animations: {
                self.isSelected = !self.isSelected
                //to-do
                closure()
                image.transform = .identity
            }, completion: nil)
        }
        
    }
}

Cómo utilizar

 @IBAction func checkbox(_ sender: UIButton){
        sender.checkboxAnimation {
            print("I'm done")
            //here you can also track the Checked, UnChecked state with sender.isSelected
            print(sender.isSelected)
            
        }
}

Verifique mi ejemplo de casilla de verificación y botón de opción https://github.com/rashidlatif55/CheckBoxAndRadioButton

Rashid Latif
fuente
2
Creo que esto merece más votos. Gracias por la elegante solución.
Carlo
obtengo un cuadrado azul cuando selecciono el botón. ¿Cómo puedo hacerlo circular
Danu
1
@danu para hacer un círculo, puede agregar esta línea didSet checkBoxOutlet.layer.cornerRadius = checkBoxOutlet.frame.height / 2y para eliminar el azul tintcuando se selecciona el botón, puede agregar estas líneas en extensión self.adjustsImageWhenHighlighted = false self.isHighlighted = false
Rashid Latif
1
@danu He creado un ejemplo para usted y proporciono un enlace en mi respuesta. Puedes jugar con eso
Rashid Latif
por lo tanto, la respuesta definitivamente merece más votos positivos gracias @RashidLatif
danu
9

Hay una biblioteca realmente excelente que puede usar para esto (en realidad puede usar esto en lugar de UISwitch): https://github.com/Boris-Em/BEMCheckBox

La configuración es sencilla:

BEMCheckBox *myCheckBox = [[BEMCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[self.view addSubview:myCheckBox];

Proporciona casillas de verificación de tipo círculo y cuadrado

ingrese la descripción de la imagen aquí

Y también hace animaciones:

ingrese la descripción de la imagen aquí

Calvin Alvin
fuente
4

Un control de casilla de verificación muy simple.

 @IBAction func btn_box(sender: UIButton) {
    if (btn_box.selected == true)
    {
        btn_box.setBackgroundImage(UIImage(named: "box"), forState: UIControlState.Normal)

            btn_box.selected = false;
    }
    else
    {
        btn_box.setBackgroundImage(UIImage(named: "checkBox"), forState: UIControlState.Normal)

        btn_box.selected = true;
    }
}
Pragnesh Vitthani
fuente
4

Versión ios swift 4 más corta:

@IBAction func checkBoxBtnTapped(_ sender: UIButton) {
        if checkBoxBtn.isSelected {
            checkBoxBtn.setBackgroundImage(#imageLiteral(resourceName: "ic_signup_unchecked"), for: .normal)
        } else {
            checkBoxBtn.setBackgroundImage(#imageLiteral(resourceName: "ic_signup_checked"), for:.normal)
        }
        checkBoxBtn.isSelected = !checkBoxBtn.isSelected
    }
Gulz
fuente
1
¡Esta respuesta es simple y logra el mismo resultado con menos código! +1
Julian Silvestri
4

Solución para Radio Button en Swift 4.2 sin usar bibliotecas de terceros

Cree el archivo RadioButtonController.swift y coloque el siguiente código en él:

import UIKit

class RadioButtonController: NSObject {
    var buttonsArray: [UIButton]! {
        didSet {
            for b in buttonsArray {
                b.setImage(UIImage(named: "radio_off"), for: .normal)
                b.setImage(UIImage(named: "radio_on"), for: .selected)
            }
        }
    }
    var selectedButton: UIButton?
    var defaultButton: UIButton = UIButton() {
        didSet {
            buttonArrayUpdated(buttonSelected: self.defaultButton)
        }
    }

    func buttonArrayUpdated(buttonSelected: UIButton) {
        for b in buttonsArray {
            if b == buttonSelected {
                selectedButton = b
                b.isSelected = true
            } else {
                b.isSelected = false
            }
        }
    }
}

Úselo como se muestra a continuación en su archivo de controlador de vista:

import UIKit

class CheckoutVC: UIViewController {

    @IBOutlet weak var btnPaytm: UIButton!
    @IBOutlet weak var btnOnline: UIButton!
    @IBOutlet weak var btnCOD: UIButton!

    let radioController: RadioButtonController = RadioButtonController()

    override func viewDidLoad() {
        super.viewDidLoad()

        radioController.buttonsArray = [btnPaytm,btnCOD,btnOnline]
        radioController.defaultButton = btnPaytm
    }

    @IBAction func btnPaytmAction(_ sender: UIButton) {
        radioController.buttonArrayUpdated(buttonSelected: sender)
    }

    @IBAction func btnOnlineAction(_ sender: UIButton) {
        radioController.buttonArrayUpdated(buttonSelected: sender)
    }

    @IBAction func btnCodAction(_ sender: UIButton) {
        radioController.buttonArrayUpdated(buttonSelected: sender)
    }
}

Asegúrese de agregar imágenes radio_off y radio_on en Activos.

radio en la imagen radio apagado imagen

Resultado:

resultado del botón de radio

Akhilendra Singh
fuente
1
Solución limpia y reutilizable. ¡Gracias!
rak appdev
¡¡¡Preciso!!! Esta fue una respuesta más consistente. Fuera de la RadioButtonControllerinstancia, usé verificar la etiqueta de selectedButtonpara distinguir qué se ha seleccionado. ¡Gracias hombre!
Randika Vishman
2

Pasos para crear un botón de opción

BasicStep: tome Two Button. establecer la imagen tanto para los seleccionados como para los no seleccionados. que agregar acción a ambos botones. ahora inicia el código

1) Crear variable:

var btnTag    : Int = 0

2) En ViewDidLoad, defina:

 btnTag = btnSelected.tag

3) Ahora en acción de toque seleccionada:

 @IBAction func btnSelectedTapped(sender: AnyObject) {
    btnTag = 1
    if btnTag == 1 {
      btnSelected.setImage(UIImage(named: "icon_radioSelected"), forState: .Normal)
      btnUnSelected.setImage(UIImage(named: "icon_radioUnSelected"), forState: .Normal)
     btnTag = 0
    }
}

4) Hacer código para el botón UnCheck

 @IBAction func btnUnSelectedTapped(sender: AnyObject) {
    btnTag = 1
    if btnTag == 1 {
        btnUnSelected.setImage(UIImage(named: "icon_radioSelected"), forState: .Normal)
        btnSelected.setImage(UIImage(named: "icon_radioUnSelected"), forState: .Normal)
        btnTag = 0
    }
}

El botón de radio está listo para ti

Krutarth Patel
fuente
2

Para una casilla de verificación, no es necesario crear una subclase del botón UIB. Ya tiene la isSelectedpropiedad para manejar esto.

checkbox = UIButton.init(type: .custom)
checkbox.setImage(UIImage.init(named: "iconCheckboxOutlined"), for: .normal)
checkbox.setImage(UIImage.init(named: "iconCheckboxFilled"), for: .selected)
checkbox.addTarget(self, action: #selector(self.toggleCheckboxSelection), for: .touchUpInside)

Luego, en el método de acción, cambie su isSelectedestado.

@objc func toggleCheckboxSelection() {
    checkbox.isSelected = !checkbox.isSelected
}
Salil Dhawan
fuente
1

Hice una clase súper simple para manejar esto en una aplicación de Mac en la que estoy trabajando. Con suerte, esto es útil para alguien

Clase RadioButtonController:

class RadioButtonController: NSObject {

var buttonArray : [NSButton] = []
var currentleySelectedButton : NSButton?
var defaultButton : NSButton = NSButton() {
    didSet {
        buttonArrayUpdated(buttonSelected: self.defaultButton)
    }
}

func buttonArrayUpdated(buttonSelected : NSButton) {
    for button in buttonArray {
        if button == buttonSelected {
            currentleySelectedButton = button
            button.state = .on
        } else {
            button.state = .off
        }
    }
}

}

Implementación en View Controller:

class OnboardingDefaultLaunchConfiguration: NSViewController {

let radioButtonController : RadioButtonController = RadioButtonController()
@IBOutlet weak var firstRadioButton: NSButton!
@IBOutlet weak var secondRadioButton: NSButton!

@IBAction func folderRadioButtonSelected(_ sender: Any) {
    radioButtonController.buttonArrayUpdated(buttonSelected: folderGroupRadioButton)
}

@IBAction func fileListRadioButtonSelected(_ sender: Any) {
    radioButtonController.buttonArrayUpdated(buttonSelected: fileListRadioButton)
}

override func viewDidLoad() {
    super.viewDidLoad()
    radioButtonController.buttonArray = [firstRadioButton, secondRadioButton]
    radioButtonController.defaultButton = firstRadioButton
}

}
got2jam
fuente
0

Simplemente puede crear una subclase de UIButton y escribir su propio código de dibujo para satisfacer sus necesidades. Implementé un botón de radio como el de Android usando el siguiente código. También se puede usar en guiones gráficos. Ver ejemplo en el repositorio de Github

import UIKit

@IBDesignable
class SPRadioButton: UIButton {

@IBInspectable
var gap:CGFloat = 8 {
    didSet {
        self.setNeedsDisplay()
    }
}

@IBInspectable
var btnColor: UIColor = UIColor.green{
    didSet{
        self.setNeedsDisplay()
    }
}

@IBInspectable
var isOn: Bool = true{
    didSet{
        self.setNeedsDisplay()
    }
}

override func draw(_ rect: CGRect) {
    self.contentMode = .scaleAspectFill
    drawCircles(rect: rect)
}


//MARK:- Draw inner and outer circles
func drawCircles(rect: CGRect){
    var path = UIBezierPath()
    path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: rect.width, height: rect.height))

    let circleLayer = CAShapeLayer()
    circleLayer.path = path.cgPath
    circleLayer.lineWidth = 3
    circleLayer.strokeColor = btnColor.cgColor
    circleLayer.fillColor = UIColor.white.cgColor
    layer.addSublayer(circleLayer)

    if isOn {
        let innerCircleLayer = CAShapeLayer()
        let rectForInnerCircle = CGRect(x: gap, y: gap, width: rect.width - 2 * gap, height: rect.height - 2 * gap)
        innerCircleLayer.path = UIBezierPath(ovalIn: rectForInnerCircle).cgPath
        innerCircleLayer.fillColor = btnColor.cgColor
        layer.addSublayer(innerCircleLayer)
    }
    self.layer.shouldRasterize =  true
    self.layer.rasterizationScale = UIScreen.main.nativeScale
}

/*
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    isOn = !isOn
    self.setNeedsDisplay()
}
*/    

override func awakeFromNib() {
    super.awakeFromNib()
    addTarget(self, action: #selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
    isOn = false
}

@objc func buttonClicked(sender: UIButton) {
    if sender == self {
        isOn = !isOn
        setNeedsDisplay()
    }
}
}
Nikesh Jha
fuente
0
  1. Cree 2 botones, uno como "SÍ" y otro como "NO".
  2. Cree una propiedad BOOL Ex: isNRICitizen = false
  3. Dar la misma conexión de botón a ambos botones y establecer una etiqueta (por ejemplo: botón Sí - etiqueta 10 y No botón - etiqueta 20)
@IBAction func btnAction(_ sender:UIButton) {

isNRICitizen = sender.tag == 10 ? true : false
isNRICitizen ? self.nriCitizenBtnYes.setImage(#imageLiteral(resourceName: "radioChecked"), for: .normal) : self.nriCitizenBtnYes.setImage(#imageLiteral(resourceName: "radioUnchecked"), for: .normal)
        isNRICitizen ? self.nriCitizenBtnNo.setImage(#imageLiteral(resourceName: "radioUnchecked"), for: .normal) : self.nriCitizenBtnNo.setImage(#imageLiteral(resourceName: "radioChecked"), for: .normal)
}
Ravindra Kishan
fuente
0

Para las casillas de verificación, en realidad hay una solución incorporada en forma de accesorios UITableViewCell. Puede configurar su formulario como un UITableView en el que cada celda como una opción seleccionable y usoaccessoryType para establecer una marca de verificación para los elementos seleccionados.

Aquí hay un ejemplo de pseudocódigo:

    let items = [SelectableItem]

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


        // Get the item for the current row
        let item = self.items[indexPath.row]

        // ...dequeue and set up the `cell` as you wish...

        // Use accessoryType property to mark the row as checked or not...
        cell.accessoryType = item.selected ? .checkmark : .none
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        // Unselect row
        tableView.deselectRow(at: indexPath, animated: false)

        // Toggle selection
        let item = self.items[indexPath.row]
        item.selected = !item.selected
        tableView.reloadData()
    }

Sin embargo, los botones de opción requieren una implementación personalizada, consulte las otras respuestas.

Aron
fuente
0

La decisión de marcar o desmarcar el botón de casilla de verificación está fuera del alcance de la vista. La vista en sí solo debería ocuparse de dibujar los elementos, no de decidir sobre el estado interno de ellos. Mi implementación sugerida es la siguiente:

import UIKit

class Checkbox: UIButton {

    let checkedImage = UIImage(named: "checked")
    let uncheckedImage = UIImage(named: "uncheked")
    var action: ((Bool) -> Void)? = nil

    private(set) var isChecked: Bool = false {
        didSet{
            self.setImage(
                self.isChecked ? self.checkedImage : self.uncheckedImage,
                for: .normal
            )
        }
    }

    override func awakeFromNib() {
        self.addTarget(
            self,
            action:#selector(buttonClicked(sender:)),
            for: .touchUpInside
        )
        self.isChecked = false
    }

    @objc func buttonClicked(sender: UIButton) {
        if sender == self {
            self.action?(!self.isChecked)
        }
    }

    func update(checked: Bool) {
        self.isChecked = checked
    }
}

Se puede utilizar con Interface Builder o mediante programación. El uso de la vista podría ser el siguiente ejemplo:

let checkbox_field = Checkbox(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
checkbox_field.action = { [weak checkbox_field] checked in
    // any further checks and business logic could be done here
    checkbox_field?.update(checked: checked)
}
Soheil Novinfard
fuente
0

Swift 5.0 Botón de radio simple actualizado para Swift (sin biblioteca)

Primero configure las imágenes en el botón One Checked y Second Unchecked.

Luego proporcione 2 salidas de RadioButton.

@IBOutlet weak var radioMale: UIButton!
@IBOutlet weak var radioFemale: UIButton!

Cree IBAction con la acción de ambos botones en un método.

 @IBAction func btnRadioTapped(_ sender: UIButton) {

    radioMale.setImage(UIImage(named: "Unchecked"), for: .normal)
    radioFemale.setImage(UIImage(named: "Unchecked"), for: .normal)

    if sender.currentImage == UIImage(named: "Unchecked"){

        sender.setImage(UIImage(named: "Checked"), for: .normal)

    }else{

        sender.setImage(UIImage(named: "Unchecked"), for: .normal)
    }

}
Threadripper
fuente
0

No tengo suficiente reputación para comentar, así que dejaré mi versión de la versión de Salil Dwahan aquí. Funciona para Swift 5, XCode 11.3.

Primero coloque su botón en IB, seleccione el tipo "Personalizado" y cree una salida y una acción con el Asistente de diseño ( Ctrl+ Arrastrar). Incluya el siguiente código y debería terminar así:

class YourViewController: UIViewController {
    @IBOutlet weak var checkbox: UIButton!
    @IBAction func checkboxTapped(_ sender: UIButton) {
        checkbox.isSelected = !checkbox.isSelected
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        checkbox.setImage(UIImage.init(named: "checkMark"), for: .selected)
    }
}

¡No olvide agregar la imagen a Activos y cambiar el nombre para que coincida!

checkbox.isSelected es la forma de comprobar

Bosco Domingo
fuente
0

Aunque algunas de las respuestas mencionan correctamente que podemos usar el Estado seleccionado para establecer una imagen para el estado Seleccionado del botón, no funcionará de manera elegante cuando el botón debe tener tanto imagen como texto.

Como muchos, terminé subclasificando UIButton; sin embargo, se agregó soporte para configurar imágenes desde Interface Builder.

A continuación se muestra mi código:

import UIKit

class CustomCheckbox: UIButton {

    @IBInspectable var defaultStateImage: UIImage? = nil {
        didSet{
            self.setNeedsDisplay()
        }
    }

    @IBInspectable var selectedStateImage: UIImage? = nil {
        didSet{
            self.setNeedsDisplay()
        }
    }

    @IBInspectable var gapPadding: CGFloat = 0 {
        didSet{
            self.setNeedsDisplay()
        }
    }

    @IBInspectable var isChecked: Bool = false {
        didSet{
            self.setNeedsDisplay()
        }
    }

    var defaultImageView: UIImageView? = nil
    var selectedImageView: UIImageView? = nil

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }

    func setup() {
        if(defaultStateImage != nil) {
            defaultImageView = UIImageView(image: defaultStateImage)
            defaultImageView?.translatesAutoresizingMaskIntoConstraints = false

            addSubview(defaultImageView!)

            let length = CGFloat(16)
            titleEdgeInsets.left += length

            NSLayoutConstraint.activate([
                defaultImageView!.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: -gapPadding),
                defaultImageView!.centerYAnchor.constraint(equalTo: self.titleLabel!.centerYAnchor, constant: 0),
                defaultImageView!.widthAnchor.constraint(equalToConstant: length),
                defaultImageView!.heightAnchor.constraint(equalToConstant: length)
            ])
        }

        if(selectedStateImage != nil) {
            selectedImageView = UIImageView(image: selectedStateImage)
            selectedImageView!.translatesAutoresizingMaskIntoConstraints = false

            addSubview(selectedImageView!)

            let length = CGFloat(16)
            titleEdgeInsets.left += length

            NSLayoutConstraint.activate([
                selectedImageView!.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: -gapPadding),
                selectedImageView!.centerYAnchor.constraint(equalTo: self.titleLabel!.centerYAnchor, constant: 0),
                selectedImageView!.widthAnchor.constraint(equalToConstant: length),
                selectedImageView!.heightAnchor.constraint(equalToConstant: length)
            ])
        }

        if defaultImageView != nil {
            defaultImageView!.isHidden = isChecked
        }

        if selectedImageView != nil  {
            selectedImageView!.isHidden = !isChecked
        }

        self.addTarget(self, action: #selector(checkChanged(_:)), for: .touchUpInside)
    }

    @objc func checkChanged(_ btn : UIButton){
        self.isChecked = !self.isChecked

        if defaultImageView != nil {
            defaultImageView!.isHidden = isChecked
        }

        if selectedImageView != nil  {
            selectedImageView!.isHidden = !isChecked
        }
    }
}

Mahendra Liya
fuente