Я разрабатываю приложение, которое позволяет делать опросы. Мой макет создан из вопросов на основе 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
}
}
}