Моя имплементация радио кнопки на основе UIButton, почему-то этого нет в UIKit, хотя может понадобиться. Мой текущий проект использует Storyboard, так что она работает для встраивания в XIB, но этот класс так же можно встраивать и при программной вёрстке.
RadioButton
import UIKit
protocol RadioButtonDelegate: class {
func onClick(_ sender: UIButton)
}
/// UIButton subclass for a radio button
final class RadioButton: UIButton {
weak var delegate: RadioButtonDelegate?
var isChecked: Bool = false {
didSet {
changeImage()
}
}
/// Init programmatically
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
/// Init programmatically
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
/// Init from NIB
override func awakeFromNib() {
super.awakeFromNib()
setup()
}
private func setup() {
self.addTarget(self, action: #selector(onClick), for: UIControl.Event.touchUpInside)
}
private func changeImage() {
isChecked ? self.setImage(UIImage(named: “radioOn”), for: .normal) : self.setImage(UIImage(named: “radioOff”), for: .normal)
}
@objc
func onClick(sender: UIButton) {
if sender == self {
delegate?.onClick(self)
}
}
}
Как это работает:
isChecked
- булевская переменная, отображающая вкл/выкл кнопкиinit
иawakeFromNib
нужны для инициализирования либо программным методом, либо с помощью XIB.setup()
добавляет Target-Action и вызывает методonClick
при нажатии на кнопкуchangeImage()
меняет свойство кнопки при нажатии, например, картинку кнопкиonClick(sender: UIButton)
,delegate
иRadioButtonDelegate
необходимы для делегирования, об этом напишу подробнее позже
Картинки с названиями radioOn и radioOff - картинки для вкл/выкл кнопки. При желании картинки можно заменить и рисовать точку внутри кнопки, а можно делать self.setTitle("✅", for: .normal)
.
Использование:
В контроллере создаём кнопку с нашим классом. Это можно сделать программно, можно в XIB, принципиальной разницы нет.
@IBOutlet weak var firstRadioButton: RadioButton!
@IBOutlet weak var secondRadioButton: RadioButton!
Контроллер, в котором создаётся кнопка, необходимо расширить до RadioButtonDelegate
, а в расширении будет нужный нам функционал. В моём случае необходимо было создать две кнопки, и иметь возможность выбрать только одну из них. При включении одной выключается другая.
extension ViewController: RadioButtonDelegate {
/// Radio button logic
func onClick(_ sender: UIButton) {
guard let currentRadioButton = sender as? RadioButton else { return }
[firstRadioButton, secondRadioButton].forEach { $0.isChecked = false } // Set all to unchecked first
currentRadioButton.isChecked = !currentRadioButton.isChecked
}
}
Этот метод можно кастомизировать, добавив кнопок или изменив логику.
После этого необходимо настроить делегат для кнопки и при необходимости задать одной из кнопок значение ВКЛ
firstRadioButton.delegate = self
secondRadioButton.delegate = self
firstRadioButton.isChecked = true
Готово! Результат: