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?
Respuestas:
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
Array
para 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í .
fuente
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:
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 :
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.
fuente
Echa un vistazo a DLRadioButton . Puede agregar y personalizar botones de opción directamente desde Interface Builder. También funciona
Swift
perfectamente.Actualización: la versión
1.3.2
agregó botones cuadrados, también mejoró el rendimiento.Actualización: versión
1.4.4
agregada opción de selección múltiple, también se puede usar como casilla de verificación.Actualización: versión
1.4.7
agregada soporte de idioma RTL.fuente
multipleSelectionEnabled
yiconSquare
paraYES
.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
fuente
didSet
checkBoxOutlet.layer.cornerRadius = checkBoxOutlet.frame.height / 2
y para eliminar el azultint
cuando se selecciona el botón, puede agregar estas líneas en extensiónself.adjustsImageWhenHighlighted = false self.isHighlighted = false
Hay una biblioteca realmente excelente que puede usar para esto (en realidad puede usar esto en lugar de
UISwitch
): https://github.com/Boris-Em/BEMCheckBoxLa 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
Y también hace animaciones:
fuente
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; } }
fuente
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 }
fuente
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.
Resultado:
fuente
RadioButtonController
instancia, usé verificar la etiqueta deselectedButton
para distinguir qué se ha seleccionado. ¡Gracias hombre!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:
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
fuente
Para una casilla de verificación, no es necesario crear una subclase del botón UIB. Ya tiene la
isSelected
propiedad 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
isSelected
estado.@objc func toggleCheckboxSelection() { checkbox.isSelected = !checkbox.isSelected }
fuente
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 } }
fuente
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() } } }
fuente
@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) }
fuente
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 uso
accessoryType
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.
fuente
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) }
fuente
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) } }
fuente
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 comprobarfuente
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 } } }
fuente