Я розробляю додаток, який дозволяє проводити опитування. Мій макет генерується з питань на основі XML.
Мені потрібно створити перемикачі (один вибір) та прапорці (кілька відповідей). Я не знайшов нічого корисного для швидкого.
Хтось має ідею?
Я розробляю додаток, який дозволяє проводити опитування. Мій макет генерується з питань на основі XML.
Мені потрібно створити перемикачі (один вибір) та прапорці (кілька відповідей). Я не знайшов нічого корисного для швидкого.
Хтось має ідею?
Відповіді:
Для радіо-кнопок і чекбокс немає нічого вбудованого.
Ви можете легко реалізувати прапорці самостійно. Для кнопки UIControlStateNormal ви можете встановити unconneImage і для 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 . Ви можете додавати та налаштовувати перемикачі безпосередньо з Interface Builder. Також Swift
чудово працює з .
Оновлення: у версію 1.3.2
додано квадратні кнопки, а також покращено продуктивність.
Оновлення: версія 1.4.4
додала параметр багаторазового вибору, також можна використовувати як прапорець.
Оновлення: версія 1.4.7
додала підтримку мови RTL.
multipleSelectionEnabled
і iconSquare
в YES
.
Свіфт 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
}
Рішення для перемикача в 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 в Активи.
Результат:
RadioButtonController
екземпляром я використовував перевірку тегу, selectedButton
щоб відрізнити те, що було вибрано. Дякую людино!
Кроки для створення радіокнопки
BasicStep: візьміть дві кнопки. встановити зображення як для вибраного, так і для вибраного. ніж додати дію до обох кнопок. тепер стартовий код
1) Створити змінну:
var btnTag : Int = 0
2) У ViewDidLoad Define:
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
}
}
Радіокнопка готова для вас
Щоб встановити прапорець, вам не потрібно підкласувати кнопку UIB. Він уже має 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 і написати свій власний код малюнка відповідно до ваших потреб. Я застосував перемикач, подібний до андроїда, використовуючи наступний код. Його можна використовувати і в розкадровці. Див. Приклад у репозиторії 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
}
}
}
}
Реалізація в 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
}
}
@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 оновлена проста кнопка радіо для 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, виберіть тип «Спеціальний» і створіть розетку та дію за допомогою макета Асистента ( 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)
}
}
Не забудьте додати зображення в Активи та змінити назву на відповідність!
checkbox.isSelected
це спосіб перевірки
Хоча в деяких відповідях справедливо згадується, що ми можемо використовувати вибраний стан для встановлення зображення для вибраного стану кнопки, це не буде працювати елегантно, коли кнопка повинна мати як зображення, так і текст.
Як і багато інших, я закінчив підкласом UIButton; однак додана підтримка налаштування зображень із Interface Builder.
Нижче мій код:
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
}
}
}