Je développe une application qui permet de faire une enquête. Ma mise en page est générée à partir de questions basées sur XML.
J'ai besoin de créer des boutons radio (choix unique) et des cases à cocher (réponses multiples). Je n'ai rien trouvé d'utile pour Swift.
Est-ce que quelqu'un a une idée?
Pour les boutons radio et les cases à cocher, rien n’est intégré.
Vous pouvez vous-même mettre en œuvre des cases à cocher facilement. Vous pouvez définir une image non cochée pour votre bouton pour UIControlStateNormal et une image vérifiée pour votre UIControlStateSelected. Maintenant, lorsque vous appuyez sur le bouton, son bouton change d’image et alterne les images cochées et les images non cochées.
Pour utiliser les boutons radio, vous devez conserver une Array
pour tous les boutons que vous souhaitez utiliser comme boutons radio. Chaque fois que vous appuyez sur un bouton, vous devez décocher tous les autres boutons du tableau.
Pour les boutons radio, vous pouvez utiliser SSRadioButtonsController Vous pouvez créer un objet contrôleur et y ajouter un tableau de boutons comme
var radioButtonController = SSRadioButtonsController()
radioButtonController.setButtonsArray([button1!,button2!,button3!])
Le principe de base est quelque chose comme ceci ici .
Case à cocher
Vous pouvez créer votre propre contrôle CheckBox en étendant UIButton avec 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: UIControlState.normal)
} else {
self.setImage(uncheckedImage, for: UIControlState.normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControlEvents.touchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
if sender == self {
isChecked = !isChecked
}
}
}
Et ajoutez-le à vos vues avec Interface Builder:
Boutons Radio
Les boutons radio peuvent être résolus de la même manière.
Par exemple, la sélection de sexe classique Femme - Homme:
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
}
}
}
}
Vous pouvez lancer vos boutons radio comme ceci:
override func awakeFromNib() {
self.view.layoutIfNeeded()
womanRadioButton.selected = true
manRadioButton.selected = false
}
override func viewDidLoad() {
womanRadioButton?.alternateButton = [manRadioButton!]
manRadioButton?.alternateButton = [womanRadioButton!]
}
J'espère que ça aide.
Départ DLRadioButton . Vous pouvez ajouter et personnaliser des boutons radio directement à partir d'Interface Builder. Fonctionne également parfaitement avec Swift
.
Update: la version 1.3.2
a ajouté des boutons carrés, améliorant également les performances.
Mise à jour: la version 1.4.4
a ajouté l'option de sélection multiple, peut également être utilisée comme case à cocher.
Update: la version 1.4.7
a ajouté le support du langage RTL.
Il existe une très bonne bibliothèque que vous pouvez utiliser pour cela (vous pouvez l'utiliser à la place de UISwitch
): https://github.com/Boris-Em/BEMCheckBox
La configuration est facile:
BEMCheckBox *myCheckBox = [[BEMCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[self.view addSubview:myCheckBox];
Il propose des cases à cocher de type cercle et carré
Et il fait aussi des animations:
Un contrôle très simple de case à cocher.
@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;
}
}
Étapes pour créer un bouton radio
BasicStep: prenez Two Button. définir l'image à la fois comme sélectionnée et non sélectionnée . que d'ajouter une action à la fois le bouton . maintenant démarrer le code
1) Créer une variable:
var btnTag : Int = 0
2) Dans ViewDidLoad, définissez:
btnTag = btnSelected.tag
3) Maintenant dans l'action de tapotement sélectionnée:
@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) Code pour le bouton 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
}
}
Le bouton radio est prêt pour vous
version plus courte de l'ios Swift 4:
@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
}
Pour une case à cocher, vous n'avez pas besoin de sous-classer le UIButton. Il a déjà la propriété isSelected
pour gérer cela.
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)
Ensuite, dans la méthode d'action, basculez son état isSelected
.
@objc func toggleCheckboxSelection() {
checkbox.isSelected = !checkbox.isSelected
}
@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)
}
La décision de cocher ou de décocher le bouton de la case à cocher sort du cadre de la vue. Voir lui-même ne devrait s'occuper que de dessiner les éléments, pas de décider de l'état interne de cela. Ma mise en œuvre suggérée est la suivante:
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
}
}
Il peut être utilisé avec Interface Builder ou par programme. L'utilisation de la vue pourrait être comme dans l'exemple suivant:
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)
}
Pour les cases à cocher, il existe une solution intégrée sous la forme d'accessoires UITableViewCell. Vous pouvez configurer votre formulaire en tant que UITableView dans lequel chaque cellule est une option sélectionnable et utiliser accessoryType
pour définir une coche pour les éléments sélectionnés.
Voici un exemple de pseudo-code:
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()
}
Les boutons radio nécessitent toutefois une implémentation personnalisée, voir les autres réponses.
Vous pouvez simplement sous-classer UIButton et écrire votre propre code de dessin pour répondre à vos besoins. J'ai implémenté un bouton radio comme celui de Android à l'aide du code suivant. Il peut également être utilisé dans le storyboard . Voir l'exemple dans le repo 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()
}
}
}