Swift Check , Unchecked Button - ios

I have two modified buttons to be a checkbox with a subclass, the checkbox is siCheckbox and noCheckbox. if siCheckbox is checked the other will be unchecked.
The problem is , if i press siCheckBox again will set noCheckbox checked and siCheckBox unchecked
this is my code
import UIKit
class Paso1: UIViewController, CheckBoxDelegate {
#IBOutlet weak var siCheckBox: CheckBox!
#IBOutlet weak var noCheckBox: CheckBox!
override func viewDidLoad() {
super.viewDidLoad()
self.siCheckBox.delegate = self
self.noCheckBox.delegate = self
}
func checkBoxDidChange(checkbox: CheckBox) {
if checkbox == self.siCheckBox {
self.noCheckBox.isChecked = !checkbox.isChecked
} else {
self.siCheckBox.isChecked = !checkbox.isChecked
}
}
and this is the subclass for the buttons checkbox
protocol CheckBoxDelegate {
func checkBoxDidChange(checkbox: CheckBox) -> Void
}
import UIKit
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "check-greenb")! as UIImage
let uncheckedImage = UIImage(named: "check-baseb")! as UIImage
var delegate: CheckBoxDelegate?
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, forState: .Normal)
} else {
self.setImage(uncheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: #selector(CheckBox.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
isChecked = !isChecked
self.delegate?.checkBoxDidChange(self)
}}
is there any examples or a better way to do this?

If you don't want your button to change its checked property if it is already checked, just add conditional logic in your buttonClicked function.
func buttonClicked(sender: UIButton) {
if !isChecked {
isChecked = !isChecked
self.delegate?.checkBoxDidChange(self)
}
}

I think this is a bit complicate to do this.
What I would do :
#IBOutlet weak var siCheckBox: CheckBox!
#IBOutlet weak var noCheckBox: CheckBox!
override func viewDidLoad() {
super.viewDidLoad()
self.siCheckBox.setImage(checkedImage, forState: .Selected)
self.siCheckBox.setImage(uncheckedImage, forState: .Normal)
self.noCheckBox.setImage(checkedImage, forState: .Selected)
self.noCheckBox.setImage(uncheckedImage, forState: .Normal)
}
#IBAction func checkBoxAction(sender : UIButton) {
siCheckBox.isSelected = false
noCheckBox.isSelected = false
sender.isSelected = true
}
That way you don't even need to subclass your button and no delegate to set. Don't forget to link your two buttons to the checkbox action function ;)

Related

How can I deselect a button when other consecutive button is pressed?

I'm creating a test that has 5 buttons, each button corresponds to a specific color, the problem is that when I select a consecutive 2nd button, the previous button is still selected, how can I make my code select only one button at a time and deselect the previous one?
How can I fix this?
This is my code
class ViewController: UIViewController {
var buttonPressed: Bool = false
#IBOutlet weak var button1: UIButton!
#IBAction func buttonAction1(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button1.setImage(UIImage(named: "Bolinha-5"), for: .normal)
}
else {
buttonPressed = true
button1.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
#IBOutlet weak var button2: UIButton!
#IBAction func buttonAction2(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button2.setImage(UIImage(named: "Bolinha-5"), for: .normal)
}
else {
buttonPressed = true
button2.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
#IBOutlet weak var button3: UIButton!
#IBAction func buttonAction3(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button3.setImage(UIImage(named: "Bolinha-2"), for: .normal)
}
else {
buttonPressed = true
button3.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
#IBOutlet weak var button4: UIButton!
#IBAction func buttonAction4(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button4.setImage(UIImage(named: "Bolinha-3"), for: .normal)
}
else {
buttonPressed = true
button4.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
#IBOutlet weak var button5: UIButton!
#IBAction func buttonAction5(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button5.setImage(UIImage(named: "Bolinha-3"), for: .normal)
}
else {
buttonPressed = true
button5.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
}
What you are going to accomplish is called Radio Buttons, unfortunately iOS (unlike macOS) doesn't provide this functionality.
My suggestion takes advantage of the option to assign different images to different states in Interface Builder – in this case the Default and Selected state – and to create an outlet collection, an array representing a sequence of UI elements of the same type.
The suggestion doesn't support an empty selection, by default the first button is selected.
In ViewController
create an outlet collection
#IBOutlet var buttons : [UIButton]!
and one IBAction
#IBAction func buttonAction(_ sender: UIButton) { }
In Interface Buider
set the images to the Default and Selected states of each button in the Attribute Inspector.
connect the buttons in the proper order to the outlet collection.
assign the tags 0 to 4 to the buttons in the same order.
connect all buttons also to the (same) IBAction.
In ViewController
create a property for the tag of the currently selected button
var selectedButton = 0
in viewDidLoad select the first button
override func viewDidLoad() {
super.viewDidLoad()
buttons[selectedButton].isSelected = true
}
Complete the IBAction, it deselects the previous button and selects the current.
#IBAction func buttonAction(_ sender: UIButton) {
let tag = sender.tag
buttons[selectedButton].isSelected = false
buttons[tag].isSelected = true
selectedButton = tag
}
let's consider you have named your buttons as follows: 1st button: "opt1Button", 2nd button: "opt2Button", 3rd button: "opt3Button" and so on...
create an IBAction with name "optionSelected" The function will look like:
#IBAction func optionSelected(_ sender: UIButton) {
opt1Button.isSelected = false
opt2Button.isSelected = false
opt3Button.isSelected = false
opt4Button.isSelected = false
opt5Button.isSelected = false
sender.isSelected = true
}
As soon any of the options is selected all the buttons will go to 'isSelected' false condition i.e all the buttons will be deselected at first and the selected button will be marked as selected. Same process will be followed again when any of the button is selected, everything will get deselected and the button user has pressed will be marked as selected.
Found this answer from (https://developer.apple.com/forums/thread/685124) and it worked for me.

Radio Button Group Swift 3 Xcode 8

I have searched various sources and could not find a clear and simple solution for creating the equivalent of a radio button group in Swift 3 with Xcode 8.3 for an iOS application.
For example if I have 3 buttons in one group and only one should be selected at a time. Currently I am implementing this by changing the state of 2 buttons in the group to not selected when the other one is selected and vice versa.
#IBAction func buttonA(_ sender: Any) {
buttonB.isChecked = false
buttonC.isChecked = false
}
#IBAction func buttonB(_ sender: Any) {
buttonA.isChecked = false
buttonC.isChecked = false
}
#IBAction func buttonC(_ sender: Any) {
buttonA.isChecked = false
buttonB.isChecked = false
}
However I would expect a more efficient way to do this.
Any help on a more efficient solution will be appreciated.
You can connect all your button's IBAction to one single method.
#IBAction func buttonClick(_ sender: UISwitch) { // you're using UISwitch I believe?
}
You should add all the buttons into an array:
// at class level
var buttons: [UISwitch]!
// in viewDidLoad
buttons = [buttonA, buttonB, buttonC]
Then, write the buttonClick method like this:
buttons.forEach { $0.isChecked = false } // uncheck everything
sender.isChecked = true // check the button that is clicked on
Alternatives:
Try using a UITableView. Each row contains one option. When a row is selected, change that row's accessoryType to .checkMark and every other row's to .none.
If you are too lazy, try searching on cocoapods.org and see what other people have made.
Just make a single selector for all three button's touchUpInside event, and set radio_off image for normal state and radio_on image for selected state in your IB, then only you have to connect btnClicked method to all button's touchUpInside event
class ViewController: UIViewController {
#IBOutlet weak var btnFirst:UIButton!
#IBOutlet weak var btnSecond:UIButton!
#IBOutlet weak var btnThird:UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnClicked(sender:UIButton){
let buttonArray = [btnFirst,btnSecond,btnThird]
buttonArray.forEach{
$0?.isSelected = false
}
sender.isSelected = true
}
Depending on your UI, you could take multiple approaches.
UITableView - Use a UITableView with a checkmark decorator. If your layout for these radio buttons is fairly traditional, this is the correct paradigm. If the layout is a grid instead of a list, you could use UICollectionView.
You can use the func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) in UITableViewDelegate to capture the selection. You can call indexPathForSelectedRow on the tableView when you want to commit the change to determine which cell was selected.
Apple's tutorial on UITableView can be found at:
https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/CreateATableView.html
Manage a group of UIButtons - You could store an array of references to UIButton objects that are part of your radio button group.
protocol RadioButtonDelegate: class {
func didTapButton(_ button: UIButton)
}
class RadioButtonGroup {
private var buttons: [UIButton] = []
weak var delegate: RadioButtonDelegate?
var selectedButton: UIButton? { return buttons.filter { $0.isSelected }.first }
func addButton(_ button: UIButton) {
buttons.append(button)
}
#objc private func didTapButton(_ button: UIButton) {
button.isSelected = true
deselectButtonsOtherThan(button)
delegate?.didTapButton(button)
}
private func deselectButtonsOtherThan(_ selectedButton: UIButton) {
for button in buttons where button != selectedButton {
button.isSelected = false
}
}
}
class MyView: UIView {
private var radioButtonGroup = RadioButtonGroup()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let button1 = UIButton(type: .custom)
button1.setTitle("Eeeny", for: .normal)
let button2 = UIButton(type: .custom)
button2.setTitle("Meeny", for: .normal)
let button3 = UIButton(type: .custom)
button3.setTitle("Miny", for: .normal)
self.radioButtonGroup.addButton(button1)
self.radioButtonGroup.addButton(button2)
self.radioButtonGroup.addButton(button3)
addSubview(button1)
addSubview(button2)
addSubview(button3)
}
}
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var maleLB: UIButton!
#IBOutlet weak var femaleLB: UIButton!
#IBOutlet weak var otherLB: UIButton!
var gender = "Male"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if gender == "Male"{
femaleLB.isSelected = true
}
}
#IBAction func maleBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
femaleLB.isSelected = false
otherLB.isSelected = false
}
else{
sender.isSelected = true
femaleLB.isSelected = false
otherLB.isSelected = false
}
}
#IBAction func femaleBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
maleLB.isSelected = false
otherLB.isSelected = false
}
else{
sender.isSelected = true
maleLB.isSelected = false
otherLB.isSelected = false
}
}
#IBAction func otherBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
maleLB.isSelected = false
femaleLB.isSelected = false
}
else{
sender.isSelected = true
maleLB.isSelected = false
femaleLB.isSelected = false
}
}
}

How to give action for two radio buttons to make active one at a time?

Here I had placed two radio buttons on view controller class but unable to give logic to make a radio button active at a time can anyone help me ?
#IBAction func radioButtonAction(_ sender: KGRadioButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
workRadioButton.isSelected = false
} else{
}
}
#IBAction func WorkRadiobuttonAction(_ sender: KGRadioButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
homeRadioButton.isSelected = false
} else{
}
}
I am just using UIButton as radioButton.try like below
Create one array to store radio buttons
var radioButtonArray = [UIButton]()
Declare your radio buttons as UIButton or anyOther
#IBOutlet weak var radioButton1: UIButton!
#IBOutlet weak var radioButton2: UIButton!
Append all buttons into array
radioButtonArray.append(contentsOf: [radio1,radio2])
Set same target for all buttons
self.radioButton1.addTarget(self, action: #selector(self.folderRadioButtonClicked(_:)), for: UIControlEvents.touchUpInside)
self.radioButton2.addTarget(self, action: #selector(self.folderRadioButtonClicked(_:)), for: UIControlEvents.touchUpInside)
func folderRadioButtonClicked(_ sender:UIButton) {
for i in 0..<self.radioButtonArray.count {
if self.radioButtonArray[i] == sender{
// here you can perform what you want
self.radioButtonArray[i].setImage(UIImage(named: "checked.png"), for: UIControlState())
}else {
self.radioButtonArray[i].setImage(UIImage(named: "unchecked.png"), for: UIControlState())
}
}
}

Need to fix my checkboxes: to change states in one click instead of two clicks. Swift 3, IOS

I have multiple checkboxes that work decently.
The way it works is that there's two images (an image of a checked box OR an image of an unchecked box) that show up or disappear into my button, based on clicking that button.
For some reason when it's the first time I click a checkbox it works perfectly (changes its state to: checked or unchecked - when clicked once), but when i go to try a second, third, or fourth (etc.) checkbox, it requires two clicks to change its state (checked/unchecked).
This is annoying and confusing to the user. Is there any way around this?
Here are my last 3 checkboxes:
/////Checkboxes
#IBOutlet weak var Box49: UIButton!
#IBOutlet weak var Box50: UIButton!
#IBOutlet weak var Box51: UIButton!
var BoxON = UIImage(named: "CheckBox")
var BoxOFF = UIImage(named:"UnCheckBox")
var isBoxClicked: Bool!
override func viewDidLoad() {
super.viewDidLoad()
isBoxClicked = false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func Box49(_ sender: Any) {
if isBoxClicked == true{
isBoxClicked = false
}else{
isBoxClicked = true
}
if isBoxClicked == true{
Box49.setImage(BoxON, for: UIControlState.normal)
}else{
Box49.setImage(BoxOFF, for: UIControlState.normal)
}
}
#IBAction func Box50(_ sender: Any) {
if isBoxClicked == true{
isBoxClicked = false
}else{
isBoxClicked = true
}
if isBoxClicked == true{
Box50.setImage(BoxON, for: UIControlState.normal)
}else{
Box50.setImage(BoxOFF, for: UIControlState.normal)
}
}
#IBAction func Box51(_ sender: Any) {
if isBoxClicked == true{
isBoxClicked = false
}else{
isBoxClicked = true
}
if isBoxClicked == true{
Box51.setImage(BoxON, for: UIControlState.normal)
}else{
Box51.setImage(BoxOFF, for: UIControlState.normal)
}
}
Thanks, Dan
The issue you are using same instance property isBoxClicked with all button instead of that you need to set the image to all button for both state normal and selected and then in your button action simply changed its selected state.
Also either change your button outlet name or action name because they both are same. So it should be like this.
#IBOutlet var box49: UIButton!
#IBOutlet var box50: UIButton!
#IBOutlet var box51: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
box49.setImage(BoxOFF, for: .normal)
box49.setImage(BoxON, for: .selected)
box50.setImage(BoxOFF, for: .normal)
box50.setImage(BoxON, for: .selected)
box51.setImage(BoxOFF, for: .normal)
box51.setImage(BoxON, for: .selected)
}
And now set your button action this way.
#IBAction func box49Button(_ sender: Button) {
sender.isSelected = !sender.isSelected
}
#IBAction func box50Button(_ sender: Button) {
sender.isSelected = !sender.isSelected
}
#IBAction func box51Button(_ sender: Button) {
sender.isSelected = !sender.isSelected
}
Or you can add single button action and set that action to all three button instead of having three different action for each button like this.
#IBAction func boxButton(_ sender: Button) {
sender.isSelected = !sender.isSelected
}
you are using one instance of isBoxClicked variable for all button. You should create an array of isBoxClicked. by using array you can check further that which checkbox(UIButon) is check an which is unchecked .
var isBoxClickedArray:[int] = {0,0}
First create enum for get index of buttons
enum ButtonIndex{
case Box49
case Box50
}
assign enum value as tag in button
Box49Button.tag = ButtonIndex.Box49.rawValue
Box50Button.tag = ButtonIndex.Box50.rawValue
create one method for get action
#IBAction func actionType(_ sender: Any) {
let button = sender as! UIBarButton
if ( button.tag == ButtonIndex.BOX49.rawValue ){
print("Box49 button pressed")
if ( isBoxClicked[ButtonIndex.BOX49.rawValue] == 0 ){
print("box49 is unchecked")
isBoxClicked[ButtonIndex.BOX49.rawValue] = 1// change it's value to checked
// change image also
}else{
// box is checked
isBoxClicked[ButtonIndex.BOX49.rawValue] = 0
// change value in array and image also
}
}else{
print("Box50 button pressed")
}
}
update
declare array in viewcontroller. and assign tag on button in viewdidload or cellforrowAtindexpath if you are using tableview. for enum declare them like this
import UIKit
enum indexs : Int{
case first
case second
}
class ViewController: UIViewController {

Merge Button Actions to reduce duplication

I have the present code to allow selection of the days of the week for a repeating event. At present they are independent, and the duplication is high.
How can the buttons be refactored to reduce duplication?
// Array of days repeating:
var weekDayRepeat = [false,false,false,false,false,false,false]
var savedEventId : String = ""
#IBOutlet weak var datePickerStart: UIDatePicker!
#IBOutlet weak var datePickerEnd: UIDatePicker!
#IBOutlet weak var repeatSwitch: UISwitch!
#IBOutlet weak var monSelect: UIButton!
#IBOutlet weak var tuesSelect: UIButton!
#IBOutlet weak var wedsSelect: UIButton!
#IBOutlet weak var thursSelect: UIButton!
#IBOutlet weak var friSelect: UIButton!
#IBOutlet weak var satSelect: UIButton!
#IBOutlet weak var sunSelect: UIButton!
#IBOutlet weak var repeatingLabel: UILabel!
#IBAction func monSelect(sender: AnyObject) {
if(weekDayRepeat[0]) {
monSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
weekDayRepeat[0] = false
} else {
monSelect.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
weekDayRepeat[0] = true
}
}
#IBAction func tuesSelect(sender: AnyObject) {
if(weekDayRepeat[1]) {
tuesSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
weekDayRepeat[1] = false
} else {
tuesSelect.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
weekDayRepeat[1] = true
}
}
#IBAction func wedsSelect(sender: AnyObject) {
if(weekDayRepeat[2]) {
wedsSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
weekDayRepeat[2] = false
} else {
wedsSelect.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
weekDayRepeat[2] = true
}
}
#IBAction func thursSelect(sender: AnyObject) {
if(weekDayRepeat[3]) {
thursSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
weekDayRepeat[3] = false
} else {
thursSelect.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
weekDayRepeat[3] = true
}
}
#IBAction func friSelect(sender: AnyObject) {
if(weekDayRepeat[4]) {
friSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
weekDayRepeat[4] = false
} else {
friSelect.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
weekDayRepeat[4] = true
}
}
#IBAction func satSelect(sender: AnyObject) {
if(weekDayRepeat[5]) {
satSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
weekDayRepeat[5] = false
} else {
satSelect.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
weekDayRepeat[5] = true
}
}
#IBAction func sunSelect(sender: AnyObject) {
if(weekDayRepeat[6]) {
sunSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
weekDayRepeat[6] = false
} else {
sunSelect.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
weekDayRepeat[6] = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Set initial conditions of the page...:
repeatSwitch.on = true
datePickerStart.datePickerMode = UIDatePickerMode.Time
datePickerEnd.datePickerMode = UIDatePickerMode.Time
monSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
tuesSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
wedsSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
thursSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
friSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
satSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
sunSelect.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)
// Allow dynamically changing the mode given if repeating or not.
// If switch to repeating, then show selecting only the time and list of days to select/multi-select
repeatSwitch.addTarget(self, action: #selector(ViewController.switchChanged(_:)), forControlEvents: UIControlEvents.ValueChanged)
}
try the following code :
#IBOutlet var weekDayBtns: [UIButton]!
#IBAction func weekDayBtnAction(sender: UIButton) {
weekDayRepeat[sender.tag] = !weekDayRepeat[sender.tag]
sender.setTitleColor(weekDayRepeat[sender.tag] ? UIColor.blackColor():UIColor.lightGrayColor() , forState: UIControlState.Normal)
}
override func viewDidLoad() {
super.viewDidLoad()
weekDayBtns.forEach({$0.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Normal)})
}
create an IBOutlet Collection: #IBOutlet var weekDayBtns: [UIButton]!
create an general IBAction :#IBAction func weekDayBtnAction(sender: UIButton){}
connect the btns all to IBOutlet Collection and IBAction
set the btn tag
here are screenshots:
#Sauron: One possible solution would be the following...
if each button is given a number as its title, you could replicate the technique used to make a simple calculator, where by...
the first button is used to create IBAction / func (kept as uibutton)
Subsequent buttons are then Control-dragged to the "ViewController" in the hierarchy in 'document outline' for the storyboard
When the popup shows. Go to the middle, under "sent events" which should have the name of the first button function you created
Do the same for all the other buttons
This helps to reduce duplication of the code writing. The buttons can then later be identified by their Title. E.g.
#IBAction func numberTapped(sender: UIButton) {
let nameOfDay = sender.currentTitle
}
Thus allowing you to utilise the weekday elsewhere within the code.
Found a youtube link that may help you quickly re: the duplication...?
https://www.youtube.com/watch?v=NJHsdjH2HdY

Resources