如何在 swift (iOS) 中创建单选按钮和复选框?
Posted
技术标签:
【中文标题】如何在 swift (iOS) 中创建单选按钮和复选框?【英文标题】:How to create radio buttons and checkbox in swift (iOS)? 【发布时间】:2015-05-20 23:36:19 【问题描述】:我正在开发一个允许进行调查的应用程序。我的布局是从基于 XML 的问题生成的。
我需要创建单选按钮(单选)和复选框(多选)。我没有发现任何对 swift 有用的东西。
有人有想法吗?
【问题讨论】:
您需要创建多个按钮,背景图像为复选框图像或单选按钮图像...单击按钮,将图像更改为选定图像...应该有两组图像,即。一个被选中,另一个未选中.. 由于 Xcode/ios 不提供复选框/单选按钮,我也使用 RJV 的建议。 是的,我试过了,它工作正常。 您是否尝试使用 Cocoapods 库来制作复选框和单选按钮? 【参考方案1】:对于单选按钮和复选框,没有内置任何内容。
您可以自己轻松实现复选框。您可以为 UIControlStateNormal 按钮设置 uncheckedImage,为 UIControlStateSelected 设置 checkedImage。现在点击时,按钮将更改其图像并在选中和未选中图像之间切换。
要使用单选按钮,您必须为所有要用作单选按钮的按钮保留Array
。每当按下按钮时,您都需要取消选中数组中的所有其他按钮。
对于单选按钮,您可以使用s-s-radioButtonsController 您可以创建一个控制器对象并向其添加按钮数组,如
var radioButtonController = s-s-radioButtonsController()
radioButtonController.setButtonsArray([button1!,button2!,button3!])
主要原理类似于this here。
【讨论】:
【参考方案2】:查看DLRadioButton。您可以直接从 Interface Builder 添加和自定义单选按钮。也可以完美地与Swift
配合使用。
更新:1.3.2
版本增加了方形按钮,也提高了性能。
更新:1.4.4
版本增加了多选选项,也可以用作复选框。
更新:1.4.7
版本增加了 RTL 语言支持。
【讨论】:
我看不到如何将您的按钮用作复选框?它只有单选按钮? 要将其用作复选框,您可以将multipleSelectionEnabled
和iconSquare
设置为YES
。
嘿@DavidLiu 我很难将您的库实现到 swift 1.2。我对 iOS 应用程序非常陌生,您的 ReadMe.md 是否跳过了一些基本步骤?我很困惑!
@milap 你可以提交问题并发布示例代码吗?
这是一个实现不佳的库。【参考方案3】:
复选框
您可以创建自己的 CheckBox 控件,使用 Swift 扩展 UIButton:
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 将其添加到您的视图中:
单选按钮
单选按钮可以用类似的方法解决。
例如经典的性别选择Woman - Man:
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!]
希望对你有帮助。
【讨论】:
你有什么理由使用func buttonClicked(sender: UIButton) if sender == self if isChecked == true isChecked = false else isChecked = true
而不是:func ButtonClicked(sender: UIButton) if sender == self isChecked = !isChecked
对于 Swift 3,您需要将 buttonClicked 方法更改为 func buttonClicked(_ sender: UIButton)
第一次运行时,我的复选框看不到任何图像...它仅在单击后出现...请帮助我
嗨@Nitesh,您可以使用公共 bool 属性 isChecked 获取 Checked 状态,例如: if myCheckbox.isChecked ...
@Jerland2 不知道为什么没有看到你的任何代码。布尔值 isChecked 已连接到图像,因此必须有其他内容。【参考方案4】:
创建单选按钮的步骤
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 Button做代码
@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
单选按钮已为您准备就绪
【讨论】:
【参考方案5】:一个非常简单的复选框控件。
@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;
【讨论】:
【参考方案6】:有一个非常棒的库可供您使用(您实际上可以使用它来代替UISwitch
):https://github.com/Boris-Em/BEMCheckBox
设置很简单:
BEMCheckBox *myCheckBox = [[BEMCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[self.view addSubview:myCheckBox];
它提供了圆形和方形类型的复选框
它也做动画:
【讨论】:
【参考方案7】:较短的 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
【讨论】:
这个答案很简单,用更少的代码就能达到同样的效果! +1【参考方案8】:您可以简单地继承 UIButton 并编写自己的绘图代码以满足您的需求。我使用以下代码实现了一个类似于 android 的单选按钮。也可以在storyboard中使用。See example in Github repo
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()
【讨论】:
【参考方案9】:对于复选框,您不需要子类化 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)
然后在 action 方法中切换为isSelected
状态。
@objc func toggleCheckboxSelection()
checkbox.isSelected = !checkbox.isSelected
【讨论】:
这个答案非常简单,没有任何子类化。完美运行!【参考方案10】:-
创建 2 个按钮,一个为“YES”,另一个为“NO”。
创建一个 BOOL 属性 例如:isNRICitizen = false
为两个按钮提供相同的按钮连接并设置标签
(例如:是按钮 - 标签 10 和否按钮 - 标签 20)
@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)
【讨论】:
【参考方案11】:对于复选框,实际上有一个内置的解决方案,以 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()
但单选按钮确实需要自定义实现,请参阅其他答案。
【讨论】:
【参考方案12】:选中或取消选中复选框按钮的决定超出了视图的范围。 View 本身应该只负责绘制元素,而不是决定其内部状态。我建议的实现如下:
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)
【讨论】:
【参考方案13】:Swift 5.0 为 Swift 更新了 Simple RadioButton(无库)
首先将图像设置为按钮 One Checked 和 Second Unchecked。
然后提供2个RadioButton的Outlet。
@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)
【讨论】:
【参考方案14】:Swift 5,带动画的复选框
注意:- 如果您想在 isSelected
时删除 blue
背景,请将 UIButton 类型从 System
更改为 Custom
创建按钮的出口
@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
【讨论】:
我认为这值得更多投票。感谢您提供优雅的解决方案。 当我选择按钮时,我得到一个蓝色方块。我怎样才能使它成为圆形 @danu 使其成为圆形,您可以在didSet
checkBoxOutlet.layer.cornerRadius = checkBoxOutlet.frame.height / 2
中添加此行,并在选择按钮时删除蓝色tint
,您可以在扩展名self.adjustsImageWhenHighlighted = false self.isHighlighted = false
中添加这些行/跨度>
@danu 我为您创建了示例,并在我的答案中提供了一个链接。你可以玩这个
因此答案绝对值得更多的投票感谢@RashidLatif【参考方案15】:
我没有足够的声誉来发表评论,所以我将把我的Salil Dwahan 的版本留在这里。适用于 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
是检查方式
【讨论】:
【参考方案16】:我创建了一个超级简单的类来在我正在开发的 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
【讨论】:
【参考方案17】:不使用第三方库的 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)
一定要在 Assets 中添加 radio_off 和 radio_on 图片。
结果:
【讨论】:
简洁且可重复使用的解决方案。谢谢! 精确!!!这是一个更体面的答案。在RadioButtonController
实例中,我使用检查selectedButton
的标签来区分选择了什么。谢谢大佬!【参考方案18】:
虽然有些答案正确地提到了我们可以使用 Selected State 为按钮的 Selected 状态设置图像,但当按钮必须同时具有图像和文本时,它不会优雅地工作。
像许多人一样,我通过继承 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
【讨论】:
【参考方案19】:在此线程中找不到简单的 SwiftUI 版本,因此这里有一个使用 SF 符号的快速组件。
struct CheckBox: View
private let checked = Image("checkmark.square.fill")
private let unChecked = Image("checkmark.square")
@State private var isChecked: Bool = false
var body: some View
ZStack
isChecked == false ? unChecked : checked
.onTapGesture
isChecked.toggle()
【讨论】:
以上是关于如何在 swift (iOS) 中创建单选按钮和复选框?的主要内容,如果未能解决你的问题,请参考以下文章