如何在Swift(iOS)中创建单选按钮和复选框?


82

我正在开发一个可以进行调查的应用程序。我的布局是根据基于XML的问题生成的。

我需要创建单选按钮(单选)和复选框(多个答案)。我没有发现任何有助于快速解决问题的方法。

有人有主意吗?


5
您需要创建带有背景图像的多个按钮,如CheckBox图像或单选按钮图像...单击按钮,将图像更改为选定图像...应具有两组图像,即。一个被选择,另一个未选..
RJV库马尔

2
由于Xcode / iOS不提供复选框/单选按钮,因此我也使用RJV的建议。
比斯塔2015年

是的,我尝试过,它正在工作。
Vannian 2015年

您是否尝试将Cocoapods库用于复选框和单选按钮?
Wimukthi Rajapaksha

Answers:


37

对于单选按钮和复选框,没有内置任何内容。

您可以自己轻松实现复选框。您可以为UIControlStateNormal的按钮设置一个uncheckedImage,为UIControlStateSelected设置一个checkedImage。现在点击,该按钮将更改其图像,并在选中和未选中的图像之间交替。

要使用单选按钮,必须对要用作单选按钮的Array所有按钮都保留一个。每当按下按钮时,您都需要取消选中阵列中的所有其他按钮。

对于单选按钮,可以使用SSRadioButtonsController。 可以创建控制器对象并向其添加按钮数组,如下所示:

var radioButtonController = SSRadioButtonsController()
radioButtonController.setButtonsArray([button1!,button2!,button3!])

其主要原理是像这样在这里


149

选框

您可以创建自己的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将其添加到您的视图中:

在此处输入图片说明

单选按钮

单选按钮可以用类似的方法解决。

例如,经典的性别选择“女人-男人”

在此处输入图片说明

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!]
    }

希望能帮助到你。


1
对于Swift 3,您需要将buttonClicked方法更改为func buttonClicked(_ sender:UIButton)
hilzj

1
第一次运行时,我的复选框看不到任何图像...仅在单击后显示...请帮助我
H Raval

2
@Nitesh,您好,您可以使用公共bool属性isChecked获得Checked状态,例如:if myCheckbox.isChecked {...}
crubio

1
@ Jerland2不知道为什么没有看到您的任何代码。boolean isChecked已连接到映像,因此必须还有其他内容。
crubio

1
@amorenew如果您仍在寻找如何在界面生成器中显示的方法,请参考我的回答。
Mahendra Liya

22

DLRadioButton。您可以直接从“界面生成器”中添加和自定义单选按钮。也Swift完美配合。

适用于iOS的Swift单选按钮

更新:版本1.3.2添加了方形按钮,还提高了性能。

更新:版本1.4.4添加了多个选择选项,也可以用作复选框。

更新:版本1.4.7添加了RTL语言支持。


我看不到如何将您的按钮用作复选框?它只有单选按钮?
dleviathan '16

1
要将其用作复选框,可以将multipleSelectionEnabled和设置iconSquareYES
David Liu

1
嘿@DavidLiu我很难实现您的库以快速1.2。我对Ios应用程序非常陌生,您的ReadMe.md是否跳过了一些基本步骤?我很困惑!
米拉普(Milap)2016年

1
@milap您可以提交问题并发布示例代码吗?
David Liu

@DavidLiu我可以使用它,只需要将您的框架添加到Embedded Binaries。可能想为超级初学者添加这一步!
米拉普(Milap)2016年

10

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


2
我认为这值得更多的选票。感谢您的优雅解决方案。
卡洛

当我选择按钮时,我会看到一个蓝色方块。我如何使其成为圆形
danu

1
@danu使其变成圆圈,您可以在中添加此行,didSet checkBoxOutlet.layer.cornerRadius = checkBoxOutlet.frame.height / 2并在tint选择按钮时删除蓝色,可以在扩展名中添加这些行 self.adjustsImageWhenHighlighted = false self.isHighlighted = false
Rashid Latif

1
我为您创建了@danu和Example,并在我的答案中提供了一个链接。你可以玩
Rashid Latif

因此,答案肯定值得更多投票支持@RashidLatif
danu

9

那里有一个非常不错的库可供您使用(您实际上可以代替UISwitch):https : //github.com/Boris-Em/BEMCheckBox

设置很简单:

BEMCheckBox *myCheckBox = [[BEMCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[self.view addSubview:myCheckBox];

它提供了圆形和正方形类型的复选框

在此处输入图片说明

它也可以做动画:

在此处输入图片说明


4

一个非常简单的复选框控件。

 @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;
    }
}

4

较短的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
这个答案很简单,用更少的代码即可达到相同的结果!+1
朱利安·西尔维斯特里

4

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图像。

影像收音机 无线电关闭图像

结果:

单选按钮结果


1
整洁且可重复使用的解决方案。谢谢!
rak appdev

精确!!!这是更大的答案。在RadioButtonController实例之外,我使用签出标签selectedButton来区分选择了什么。谢啦!
Randika Vishman

2

创建单选按钮的步骤

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
    }
}

单选按钮已为您准备就绪


2

对于复选框,您不需要子类化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
}

1

我制作了一个超级简单的类来在我正在使用的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
}

}

0

您可以简单地子类化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()
    }
}
}

0
  1. 创建2个按钮,一个为“ YES”,另一个为“ NO”。
  2. 创建一个BOOL属性,例如:isNRICitizen = false
  3. 为两个按钮提供相同的按钮连接并设置标签(例如:是按钮-标签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)
}

0

对于复选框,实际上有一个内置解决方案,形式为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()
    }

但是,单选按钮确实需要自定义实现,请参见其他答案。


0

选中或取消选中复选框按钮的决定超出了视图的范围。视图本身仅应考虑绘制元素,而不要决定其内部状态。我建议的实现如下:

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)
}

0

Swift 5.0更新了用于Swift的Simple RadioButton(无库)

首先将图像设置为“已选中”和“未选中”按钮。

然后提供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)
    }

}

0

我没有足够的声誉来发表评论,所以这里将我的Salil Dwahan版本保留下来。适用于Swift 5,XCode 11.3。

首先将您的按钮放在IB上,选择类型“ Custom”,然后使用Assistant Layout(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 是检查的方法


0

尽管某些答案正确地提到了我们可以使用“选定状态”为按钮的“选定状态”设置图像,但是当按钮必须同时具有图像和文本时,它不能很好地工作。

像许多人一样,我以继承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
        }
    }
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.