Я разрабатываю приложение, которое позволяет делать опросы. Мой макет создан из вопросов на основе XML.
Мне нужно создать переключатели (один вариант) и флажки (несколько ответов). Для swift ничего полезного не нашел.
Есть у кого-нибудь идеи?
Я разрабатываю приложение, которое позволяет делать опросы. Мой макет создан из вопросов на основе XML.
Мне нужно создать переключатели (один вариант) и флажки (несколько ответов). Для swift ничего полезного не нашел.
Есть у кого-нибудь идеи?
Ответы:
Для радиокнопок и флажков нет ничего встроенного.
Вы можете легко реализовать флажки самостоятельно. Вы можете установить uncheckedImage для своей кнопки для UIControlStateNormal и checkedImage для своего UIControlStateSelected. Теперь при нажатии кнопка изменит свое изображение и будет переключаться между отмеченным и непроверенным изображением.
Чтобы использовать радиокнопки, вы должны оставить Arrayдля всех кнопок, которые вы хотите использовать как радиокнопки. Каждый раз, когда нажимается кнопка, вам необходимо снять отметку со всех других кнопок в массиве.
Для переключателей вы можете использовать SSRadioButtonsController. Вы можете создать объект контроллера и добавить к нему массив кнопок, например
var radioButtonController = SSRadioButtonsController()
radioButtonController.setButtonsArray([button1!,button2!,button3!])
Главный принцип здесь примерно такой .
Флажок
Вы можете создать свой собственный элемент управления CheckBox, расширяющий UIButton с помощью 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
}
}
}
А затем добавьте его в свои представления с помощью Interface Builder:
Радио-кнопки
Радио-кнопки решаются аналогичным образом.
Например, классический выбор пола Женщина - Мужчина :
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
}
}
}
}
Вы можете настроить свои переключатели следующим образом:
override func awakeFromNib() {
self.view.layoutIfNeeded()
womanRadioButton.selected = true
manRadioButton.selected = false
}
override func viewDidLoad() {
womanRadioButton?.alternateButton = [manRadioButton!]
manRadioButton?.alternateButton = [womanRadioButton!]
}
Надеюсь, поможет.
Проверьте DLRadioButton . Вы можете добавлять и настраивать переключатели непосредственно из Интерфейсного разработчика. Также Swiftотлично работает с .
Обновление: в версии 1.3.2добавлены квадратные кнопки, также улучшена производительность.
Обновление: в версии 1.4.4добавлена опция множественного выбора, также может использоваться как флажок.
Обновление: в версию 1.4.7добавлена поддержка языка RTL.
multipleSelectionEnabledи iconSquareна YES.
Swift 5, флажок с анимацией
Создаем розетку кнопки
@IBOutlet weak var checkBoxOutlet:UIButton!{
didSet{
checkBoxOutlet.setImage(UIImage(named:"unchecked"), for: .normal)
checkBoxOutlet.setImage(UIImage(named:"checked"), for: .selected)
}
}
Создайте расширение 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)
}
}
}
Как пользоваться
@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)
}
}
Проверьте мой пример для флажка и переключателя https://github.com/rashidlatif55/CheckBoxAndRadioButton
didSet checkBoxOutlet.layer.cornerRadius = checkBoxOutlet.frame.height / 2И чтобы удалить синий цвет, tintкогда кнопка выбрана, вы можете добавить эту строку в расширение self.adjustsImageWhenHighlighted = false self.isHighlighted = false
Есть действительно отличная библиотека, которую вы можете использовать для этого (вы действительно можете использовать ее вместо UISwitch): https://github.com/Boris-Em/BEMCheckBox
Настройка проста:
BEMCheckBox *myCheckBox = [[BEMCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[self.view addSubview:myCheckBox];
Предусмотрены флажки круглого и квадратного типа.
А еще делает анимацию:
Очень простой элемент управления флажком.
@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;
}
}
короче версия 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
}
Решение для Radio Button в Swift 4.2 без использования сторонних библиотек
Создайте файл RadioButtonController.swift и поместите в него следующий код:
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
}
}
}
}
Используйте его, как показано ниже, в файле контроллера представления:
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)
}
}
Обязательно добавьте изображения radio_off и radio_on в Assets.
Результат:
RadioButtonControllerэкземпляра я использовал проверку тега, selectedButtonчтобы отличить то, что было выбрано. Спасибо чувак!
Шаги по созданию радиокнопки
BasicStep: возьмите две кнопки. установить изображение как для выбранного, так и для невыделенного. чем добавить действие к обеим кнопкам. теперь начните код
1) Создайте переменную:
var btnTag : Int = 0
2) В ViewDidLoad определите:
btnTag = btnSelected.tag
3) Теперь в выбранном действии касания:
@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) Сделайте код для кнопки 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
}
}
Радиокнопка готова для вас
Для флажка не нужно создавать подкласс UIButton. У него уже есть isSelectedвозможность справиться с этим.
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)
Затем в методе действия переключите его isSelectedсостояние.
@objc func toggleCheckboxSelection() {
checkbox.isSelected = !checkbox.isSelected
}
Вы можете просто создать подкласс UIButton и написать свой собственный код рисования в соответствии с вашими потребностями. Я реализовал радиокнопку, подобную той, что есть в android, используя следующий код. Его также можно использовать в раскадровке. См. Пример в репозитории 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()
}
}
}
Я сделал супер простой класс для решения этой проблемы в приложении Mac, над которым я работаю. Надеюсь, это кому-то поможет
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
}
}
}
}
Реализация в контроллере представления:
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
}
}
@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)
}
Для флажков есть встроенное решение в виде аксессуаров UITableViewCell. Вы можете настроить свою форму как UITableView, в котором каждая ячейка является выбираемым параметром и использовать accessoryTypeдля установки флажка для выбранных элементов.
Вот пример псевдокода:
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()
}
Однако радиокнопки требуют специальной реализации, см. Другие ответы.
Решение о том, поставить или снять отметку с кнопки флажка, выходит за рамки представления. Само представление должно заботиться только о рисовании элементов, а не о их внутреннем состоянии. Моя предлагаемая реализация выглядит следующим образом:
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
}
}
Его можно использовать с Interface Builder или программно. Использование представления может быть следующим примером:
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)
}
Swift 5.0 обновил Simple RadioButton для Swift (без библиотеки)
Сначала установите изображения на кнопку «Один установлен» и «Второй не отмечен».
Затем предоставьте 2 выхода RadioButton.
@IBOutlet weak var radioMale: UIButton!
@IBOutlet weak var radioFemale: UIButton!
Создайте IBAction с действием обеих кнопок одним методом.
@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)
}
}
У меня недостаточно репутации, чтобы давать комментарии, поэтому я оставлю здесь свою версию версии Салила Двахана . Работает для Swift 5, XCode 11.3.
Сначала поместите свою кнопку на IB, выберите тип «Custom» и создайте выход и действие с помощью макета помощника ( Ctrl+ перетаскивание). Включите следующий код, и он должен заканчиваться так:
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)
}
}
Не забудьте добавить изображение в Assets и изменить имя, чтобы оно соответствовало!
checkbox.isSelected это способ проверить
Хотя в некоторых ответах правильно упоминается, что мы можем использовать Selected State для установки изображения для выбранного состояния кнопки, это не будет работать элегантно, когда кнопка должна иметь и изображение, и текст.
Как и многие, я закончил тем, что создал подкласс UIButton; однако добавлена поддержка установки изображений из Интерфейсного разработчика.
Ниже мой код:
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
}
}
}