checkbox save/load NSUserdefaults - ios

I have this app with two checkboxes that I want to save when I close and load when I open but I cannot figure it out. Please can someone help me edit the code. I know need to save in UserDefaults somehow but I don't know how to code it.
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "checked")! as UIImage
let uncheckedImage = UIImage(named: "unchecked")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, for: UIControlState.normal)
} else {
self.setImage(uncheckedImage, for: UIControlState.normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControlEvents.touchUpInside)
self.isChecked = false
}
#objc func buttonClicked(sender: UIButton) {
if sender == self {
isChecked = !isChecked
}
}
}

Use following to save bool value to UserDefaults:
UserDefaults.standard.set(isChecked, forKey: "com.myCompany.checkboxState")
And load it using:
self.isChecked = UserDefaults.standard.bool(forKey: "com.myCompany.checkboxState")
Read more in documentation for UserDefaults.
Just remember that if you have several checkBoxes, you have to use unique key for each one, e.g. use UIButton's tag to differentiate between them:
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "checked")! as UIImage
let uncheckedImage = UIImage(named: "unchecked")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, for: UIControlState.normal)
} else {
self.setImage(uncheckedImage, for: UIControlState.normal)
}
// save it like this
UserDefaults.standard.set(isChecked, forKey: "com.myCompany.checkboxStateFor\(self.tag)")
}
}
override func awakeFromNib() {
self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControlEvents.touchUpInside)
// load it like this
self.isChecked = UserDefaults.standard.bool(forKey: "com.myCompany.checkboxStateFor\(self.tag)")
}
#objc func buttonClicked(sender: UIButton) {
if sender == self {
isChecked = !isChecked
}
}
}
Then don't forget to setup a different tag for each checkBox in your app.

Probably something like this you are looking for?
extension UserDefaults{
func setChecked(value: Bool, forId id: String){
set(value, forKey: id)
}
func getChecked(forId id: String) -> Int{
return bool(forKey: id)
}
}
use:
UserDefaults.standard.setChecked(true, "box1")
UserDefaults.standard.getChecked("box1")

override func awakeFromNib() {
self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControlEvents.touchUpInside)
isChecked = UserDefaults.standard.bool(forKey: "buttonChecked")
}
#objc func buttonClicked(sender: UIButton) {
isChecked = !isChecked
UserDefaults.standard.set(isChecked, forKey: "buttonChecked")
}

Related

Unable to change image for the button in swift 3?

In my code for checkmark I used button to change images for selected and unselected but unable to implement if I click on it's changing to unchecked but again selecting button it's unable to change to check image can anyone help me how to resolve this ?
var checkedImage = UIImage(named: "check")! as UIImage
var uncheckedImage = UIImage(named: "uncheck")! as UIImage
var isChecked: Bool = true
var checkMarkSelected = 0
checkMarkButton.addTarget(self, action: #selector(checkMarkAction(button:)), for: .touchUpInside)
func checkMarkAction(button : UIButton) {
if isChecked == true {
checkMarkButton.setImage(checkedImage, for: .selected)
isChecked = false
checkMarkSelected = 1
}
else {
checkMarkButton.setImage(uncheckedImage, for: .normal)
isChecked = true
checkMarkSelected = 0
}
}
Step 1: Select your CheckUIButton and set Image “Uncheck” (state config must be Default in attribute inspector)
Step 2: In attribute inspector change state config to Selected and set image “Check”
Step 3: Put following code in your UIButton action.
#IBAction func checkclick(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
}
In Swift 3
#IBAction func btntouchupInsideevent(_ sender: UIButton)
{
if yourbtnOutletName.currentImage == "YourCheckImageName"
{
yourbtnOutletName.setImage(YourUncheckImage.imagetype, for: .normal)
}
else
{
btnIsEventRecouring.setImage(YourcheckImage.imagetype, for: .normal)
}
}
I think that you should add the action in the viewDidLoad() function of your view controller for that button or, if you are declaring it in a stand-alone UIButton inherited class in order to reuse it in the future in many view controllers, you should add the target in the initialiser of the UIButton.
If the code is written in that way is even strange that Xcode is not giving you warnings...
EDIT: This is a code snippet of how I would do it
//Comments
import UIKit
class ViewController: UIViewController {
//link this to the checkmark buttons
//subclass UIButton making a button with the property isChecked: Bool
#IBOutlet weak var checkmarkButton: UICheckButton!
var checkMarkSelected = 0
override function viewDidLoad() {
//do stuff with your viewdidload
}
//link this to the checkmark buttons
#IBAction func checkMarkAction(sender: UICheckButton) {
if sender.isChecked == false {
let checkedImage = UIImage(named: "check")
checkMarkButton.setImage(checkedImage, for: .normal)
sender.isChecked = true
checkMarkSelected += checkMarkSelected
} else {
let uncheckedImage = UIImage(named: "uncheck")
checkMarkButton.setImage(uncheckedImage, for: .normal)
sender.isChecked = false
checkMarkSelected -= checkMarkSelected
}
}
In Swift 4:
#IBOutlet weak var termsAndConditionsButton: UIButton!
if termsAndConditionsButton.isSelected == true {
termsAndConditionsButton.setImage(UIImage(named: "checkboxOff"), for: .normal)
termsAndConditionsButton.isSelected=false
}
else{
termsAndConditionsButton.setImage(UIImage(named: "checkboxOn"), for: .normal)
termsAndConditionsButton.isSelected=true
}
Try with this on IBAction function
sender.isSelected = !sender.isSelected
if sender.isSelected == true {
sender.isSelected = true
sender.setImage(UIImage(named: "img_on"), for: UIControl.State.selected)
}else{
sender.isSelected = false
sender.setImage(UIImage(named: "img_off"), for: UIControl.State.normal)
}

Set CheckBox on - off

I made a custom checkbox with button by creatin a class of UIButton
here is the class
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, forState: .Normal)
} else {
self.setImage(uncheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
if sender == self {
isChecked = !isChecked
}
}
}
I have two checkboxes in the viewcontroller but I dont know how to set checkbox in the ViewController.class to do when checkBox "Si" is checked, the checkbox "No" set unchecked like in the image
Your CheckBox class should adopt a delegation pattern so that it can advise its delegate (which in this case would be your view controller) that its value has changed. Then in your view controller you can update the other checkbox as required:
protocol CheckBoxDelegate {
func checkBoxDidChange(checkbox: CheckBox) -> Void
}
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "ic_check_box")! as UIImage
let uncheckedImage = UIImage(named: "ic_check_box_outline_blank")! as UIImage
weak 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: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
isChecked = !isChecked
self.delegate?.checkBoxDidChange(self)
}
}
Then, in your View Controller:
class ViewController: UIViewController, CheckBoxDelegate {
#IBOutlet var siCheckBox: CheckBox! // Initialise some other way if you aren't using storyboard/nib
#IBOutlet var noCheckBox: CheckBox!
override func viewDidLoad() {
super.viewDidLoad()
self.siCheckBox.delegate = self
self.noCheckBox.delegate = self
}
//Mark: CheckBoxDelegate
func checkBoxDidChange(checkbox: CheckBox) {
if checkbox == self.siCheckBox {
self.noCheckBox.isChecked = !checkbox.isChecked
} else {
self.siCheckBox.isChecked = !checkbox.isChecked
}
}
From a user experience point of view, I would question why you need both checkboxes. A checkbox is an on/off control, so you would normally have text like "Select really great option?" with a single checkbox for yes/no; checked is yes, unchecked is no.
I would move func buttonClicked(sender: UIButton) to the parent ViewController.
let siCheckBox = CheckBox()
let noCheckBox = CheckBox()
func checkBoxToggled(sender: AnyObject) {
noCheckbox.isChecked = !noCheckbox.isChecked
siCheckbox.isChecked = !siCheckbox.isChecked
}
This is only safe if you're sure at least 1 is always checked. Otherwise I would add an if statement to make sure at l is checked.

How to toggle a UITextField secure text entry (hide password) in Swift?

I currently have a UITextfield with an eye icon in it that when pressed is supposed to toggle the secure text entry on and off.
I know you can check mark the "secure text entry" box in the attributes inspector but how to do it so it toggles whenever the icon is pressed?
Use this code,
iconClick is bool variable, or you need other condition check it,
var iconClick = true
eye Action method:
#IBAction func iconAction(sender: AnyObject) {
if iconClick {
passwordTF.secureTextEntry = false
} else {
passwordTF.secureTextEntry = true
}
iconClick = !iconClick
}
hope its helpful
An unintended side-effect of this is that if the user toggles to insecure, and then back to secure, the existing text will be cleared if the user continues typing. The cursor may also end up in the wrong position unless we reset the selected text range.
Below is an implementation that handles these cases (Swift 4)
extension UITextField {
func togglePasswordVisibility() {
isSecureTextEntry = !isSecureTextEntry
if let existingText = text, isSecureTextEntry {
/* When toggling to secure text, all text will be purged if the user
continues typing unless we intervene. This is prevented by first
deleting the existing text and then recovering the original text. */
deleteBackward()
if let textRange = textRange(from: beginningOfDocument, to: endOfDocument) {
replace(textRange, withText: existingText)
}
}
/* Reset the selected text range since the cursor can end up in the wrong
position after a toggle because the text might vary in width */
if let existingSelectedTextRange = selectedTextRange {
selectedTextRange = nil
selectedTextRange = existingSelectedTextRange
}
}
}
This snippet is using the replace(_:withText:) function because it triggers the .editingChanged event, which happens to be useful in my application. Just setting text = existingText should be fine as well.
Why to use an extra var. In the action method of the eye button just do as below
password.secureTextEntry = !password.secureTextEntry
UPDATE
Swift 4.2 (as per #ROC comment)
password.isSecureTextEntry.toggle()
I wrote extension for the same. To provide Password toggle.
In your Assets first add images that you want for toggle.
Add following extension for UITextField.
extension UITextField {
fileprivate func setPasswordToggleImage(_ button: UIButton) {
if(isSecureTextEntry){
button.setImage(UIImage(named: "ic_password_visible"), for: .normal)
}else{
button.setImage(UIImage(named: "ic_password_invisible"), for: .normal)
}
}
func enablePasswordToggle(){
let button = UIButton(type: .custom)
setPasswordToggleImage(button)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -16, bottom: 0, right: 0)
button.frame = CGRect(x: CGFloat(self.frame.size.width - 25), y: CGFloat(5), width: CGFloat(25), height: CGFloat(25))
button.addTarget(self, action: #selector(self.togglePasswordView), for: .touchUpInside)
self.rightView = button
self.rightViewMode = .always
}
#IBAction func togglePasswordView(_ sender: Any) {
self.isSecureTextEntry = !self.isSecureTextEntry
setPasswordToggleImage(sender as! UIButton)
}
}
Call extension on your UITextField Outlet
override func viewDidLoad() {
super.viewDidLoad()
txtPassword.enablePasswordToggle()
txtConfirmPassword.enablePasswordToggle()
}
Swift 4 solution
You don't need extra if statement for simple toggle isSecureTextEntry property
func togglePasswordVisibility() {
password.isSecureTextEntry = !password.isSecureTextEntry
}
But there is a problem when you toggle isSecureTextEntry UITextField doesn't recalculate text width and we have extra space to the right of the text. To avoid this you should replace text this way
func togglePasswordVisibility() {
password.isSecureTextEntry = !password.isSecureTextEntry
if let textRange = password.textRange(from: password.beginningOfDocument, to: password.endOfDocument) {
password.replace(textRange, withText: password.text!)
}
}
UPDATE
Swift 4.2
Instead of
password.isSecureTextEntry = !password.isSecureTextEntry
you can do this
password.isSecureTextEntry.toggle()
Use UITextFiled rightView to show toggle button
var rightButton = UIButton(type: .custom)
rightButton.frame = CGRect(x:0, y:0, width:30, height:30)
yourtextfield.rightViewMode = .always
yourtextfield.rightView = rightButton
If you need TextField with similar feature in multiple places its best to subclass the UITextField like follwing example -
import UIKit
class UIShowHideTextField: UITextField {
let rightButton = UIButton(type: .custom)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
required override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
rightButton.setImage(UIImage(named: "password_show") , for: .normal)
rightButton.addTarget(self, action: #selector(toggleShowHide), for: .touchUpInside)
rightButton.frame = CGRect(x:0, y:0, width:30, height:30)
rightViewMode = .always
rightView = rightButton
isSecureTextEntry = true
}
#objc
func toggleShowHide(button: UIButton) {
toggle()
}
func toggle() {
isSecureTextEntry = !isSecureTextEntry
if isSecureTextEntry {
rightButton.setImage(UIImage(named: "password_show") , for: .normal)
} else {
rightButton.setImage(UIImage(named: "password_hide") , for: .normal)
}
}
}
After which you can use it in any ViewController,
class ViewController: UIViewController {
#IBOutlet var textField: UIShowHideTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.becomeFirstResponder()
}
}
For Objective c
set image for RightButton In viewdidload Method
[RightButton setImage:[UIImage imageNamed:#"iconEyesOpen"] forState:UIControlStateNormal];
[RightButton setImage:[UIImage imageNamed:#"iconEyesClose"] forState:UIControlStateSelected];
and then set action method for that RightButton
-(IBAction)RightButton:(id)sender
{
if (_rightButton.selected)
{
_rightButton.selected = NO;
_passwordText.secureTextEntry = YES;
if (_passwordText.isFirstResponder) {
[_passwordText resignFirstResponder];
[_passwordText becomeFirstResponder];
}
}
else
{
_rightButton.selected = YES;
_passwordText.secureTextEntry = NO;
if (_passwordText.isFirstResponder) {
[_passwordText resignFirstResponder];
[_passwordText becomeFirstResponder];
}
}
}
Swift 3
// MARK: Btn EyeAction
#IBAction func btnEyeAction(_ sender: Any) {
if(iconClick == true) {
txtPassword.isSecureTextEntry = false
iconClick = false
} else {
txtPassword.isSecureTextEntry = true
iconClick = true
}
}
Shortest!
I think this is the shortest solution for secure entry as well as updating the picture of the button.
#IBAction func toggleSecureEntry(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
textfieldPassword.isSecureTextEntry = !sender.isSelected
}
Assign the show/hide picture of the button according to the state selected /default , no need to create any variable or outlet.
This worked for me on Swift 5.0
#IBAction func changePasswordVisibility(_ sender: UIButton) {
passwordField.isSecureTextEntry.toggle()
if passwordField.isSecureTextEntry {
if let image = UIImage(systemName: "eye.fill") {
sender.setImage(image, for: .normal)
}
} else {
if let image = UIImage(systemName: "eye.slash.fill") {
sender.setImage(image, for: .normal)
}
}
}
Button attributes:
Result:
Swift 3
passwordTF.isSecureTextEntry = true
passwordTF.isSecureTextEntry = false
#IBAction func eye_toggle_clicked(sender: AnyObject)
{
if toggleBtn.tag == 0
{
passwordTxt.secureTextEntry=true
toggleBtn.tag=1
}
else
{
passwordTxt.secureTextEntry=false
toggleBtn.tag=0
}
}
As others have noted, the property is secureTextEntry, but you won't find this in the UITextField documentation, as it is actually inherited by a UITextField through the UITextInputTraits protocol- https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/#//apple_ref/occ/intfp/UITextInputTraits/secureTextEntry
You can simply toggle this value each time your button is tapped:
#IBAction func togglePasswordSecurity(sender: UIButton) {
self.passwordField.secureTextEntry = !self.passwordField.secureTextEntry
}
try this line:
#IBAction func btnClick(sender: AnyObject) {
let btn : UIButton = sender as! UIButton
if btn.tag == 0{
btn.tag = 1
textFieldSecure.secureTextEntry = NO
}
else{
btn.tag = 0
textFieldSecure.secureTextEntry = NO;
}
}
Here is your answer no need to take any bool var:
#IBAction func showHideAction(sender: AnyObject) {
if tfPassword.secureTextEntry{
tfPassword.secureTextEntry = false
}else{
tfPassword.secureTextEntry = true;
}
}
First you need to set image(visible or hide) of button of eye for different state (selected or normal)
than connect IBAction and write code like
#IBAction func btnPasswordVisiblityClicked(_ sender: Any) {
(sender as! UIButton).isSelected = !(sender as! UIButton).isSelected
if (sender as! UIButton).isSelected {
txtfPassword.isSecureTextEntry = false
} else {
txtfPassword.isSecureTextEntry = true
}
}
In Swift 4
var iconClick : Bool!
override func viewDidLoad() {
super.viewDidLoad()
iconClick = true
}
#IBAction func showHideAction(_ sender: Any)
{
let userPassword = userPasswordTextFiled.text!;
if(iconClick == true) {
userPasswordTextFiled.isSecureTextEntry = false
iconClick = false
} else {
userPasswordTextFiled.isSecureTextEntry = true
iconClick = true
}
}
Assignment values change from YES/NO to true/false boolean values.
password.secureTextEntry = true //Visible
password.secureTextEntry = false //InVisible
You can try this code..
i think it's helpful.
Use button with eye image
and make buttonHandler method
set Tag for button with value 1
-(IBAction) buttonHandlerSecureText:(UIButton *)sender{
if(sender.tag ==1){
[self.textField setSecureTextEntry:NO];
sender.tag = 2;
}
else{
[self.textField setSecureTextEntry:YES];
sender.tag = 1;
}
}
For Xamarin folks:
passwordField.SecureTextEntry = passwordField.SecureTextEntry ? passwordField.SecureTextEntry = false : passwordField.SecureTextEntry = true;
Try this code in swift 4, tried to make a reusable code within a controller. I have set different image for buttons in storyboard as shown in the link https://stackoverflow.com/a/47669422/8334818
#IBAction func clickedShowPassword(_ sender: UIButton) {
var textField :UITextField? = nil
print("btn ",sender.isSelected.description)
switch sender {
case encryptOldPswdBtn:
encryptOldPswdBtn.isSelected = !encryptOldPswdBtn.isSelected
textField = oldPasswordTextField
default:
break
}
print("text ",textField?.isSecureTextEntry.description)
textField?.isSecureTextEntry = !(textField?.isSecureTextEntry ?? false)
}
#objc func togglePasscode(){
switch textfield.isSecureTextEntry{
case true:
textfield.isSecureTextEntry = false
case false:
textfield.isSecureTextEntry = true
}
}
Here is a easy and more readable solution using Switch statement.
Hope this is simpler solution rather than creating a BOOL object globally.
#IBAction func passwordToggleButton(sender: UIButton) {
let isSecureTextEntry = passwordTextField.isSecureTextEntry
passwordTextField.isSecureTextEntry = isSecureTextEntry ? false : true
if isSecureTextEntry {
visibilityButton.setImage(UIImage(named: "visibility"), for: .normal)
} else {
visibilityButton.setImage(UIImage(named: "visibility_off"), for: .normal)
}
}
only add this line into your code replace you TextField name with "textfield" Done:
you need to change the isSecureTextEntry propertity to change true for password type textFiled like ......
textField.isSecureTextEntry = true
sender.isSelected = !sender.isSelected
if(sender.isSelected == true) {
RegPasswordField.isSecureTextEntry = false
sender.setBackgroundImage(UIImage(systemName: "eye.fill"), for: .normal)
} else {
RegPasswordField.isSecureTextEntry = true
sender.setBackgroundImage(UIImage(systemName: "eye"), for: .normal)
}
Swift 5 Please use this
var btnClick = true
if(btnClick == true) {
passwordTextField.isSecureTextEntry = false
} else {
passwordTextField.isSecureTextEntry = true
}
btnClick = !btnClick
}
var viewingPassword = true
#IBAction func btnEyeAction(_ sender: Any) {
passwordTF.isSecureTextEntry = viewingPassword ? false : true
viewingPassword.toggle()
}

Saving state of UIButton (checkbox) - Swift

I'm a new developer and I'm making a to-do list app in Swift. I was able to figure out how to change the state of the UIButton (checkbox) on clicking. At the moment I'm trying to figure out how to save that state for when I exit the app or switch views and return. I was able to successfully save the text (to-do list tasks) by using NSUserDefaults and have also experimented with it on my buttons but cannot figure out how to get it to work.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var myButton: Qbutton!
override func viewDidLoad() {
super.viewDidLoad()
var isChecked = NSUserDefaults.standardUserDefaults().boolForKey("isBtnChecked") // here we obtain the last state of the button
myButton.isChecked = isChecked
self.view.addSubview(myButton)
I have the UIButton in a subclass of QButton.
class Qbutton: UIButton {
var isSelected: Bool = defaults.boolForKey("isButtonChecked")
// Images
let selectedImage = UIImage(named: "Selected")
let unselectedImage = UIImage(named: "Unselected")
//Bool Property
var isChecked:Bool = false{
didSet{
if isChecked == true{
self.setImage(selectedImage, forState: UIControlState.Normal)
}else{
self.setImage(unselectedImage, forState: UIControlState.Normal)
}
defaults.setObject(isChecked, forKey: "isButtonChecked")
}
}
override init(frame: CGRect){
super.init(frame:frame)
self.layer.masksToBounds = true
self.setImage(unselectedImage, forState: UIControlState.Normal)
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func buttonClicked(sender: UIButton) {
if(sender == self){
if isChecked == true{
isChecked = false
}else{
isChecked = true
}
}
}
}
well i think you can save the state of the UIButton with the NSUserDefaults just when the variable isChecked is changed. Something like this:
var isChecked:Bool = false{
didSet{
if isChecked {
self.setImage(selectedImage, forState: UIControlState.Normal)
}else{
self.setImage(unselectedImage, forState: UIControlState.Normal)
}
NSUserDefaults.standardUserDefaults().setObject(isChecked, forKey: "isBtnChecked")
// this method is automatically invoked at periodic intervals, but
//if you cannot wait for the automatic synchronization you can invoke it
NSUserDefaults.standardUserDefaults().synchronize()
}
}
Now when your app is launched you can check the last state of the UIButton with this:
var isSelected: Bool = NSUserDefaults.standardUserDefaults().boolForKey("isBtnChecked")
UPDATE
I made an example using your Qbutton class. I hope this can help you:
import Foundation
import UIKit
class Qbutton: UIButton {
// Images
let selectedImage = UIImage(named: "Selected")
let unselectedImage = UIImage(named: "Unselected")
//Bool Property
var isChecked:Bool = false{
didSet{
if isChecked {
self.setImage(selectedImage, forState: UIControlState.Normal)
}else{
self.setImage(unselectedImage, forState: UIControlState.Normal)
}
NSUserDefaults.standardUserDefaults().setObject(isChecked, forKey: "isBtnChecked")
// this method is automatically invoked at periodic intervals, but
//if you cannot wait for the automatic synchronization you can invoke it
NSUserDefaults.standardUserDefaults().synchronize()
}
}
override init(frame: CGRect){
super.init(frame:frame)
self.layer.masksToBounds = true
self.setImage(unselectedImage, forState: UIControlState.Normal)
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func buttonClicked(sender: UIButton) {
if(sender == self){
if isChecked == true{
isChecked = false
self.setImage(unselectedImage, forState: UIControlState.Normal)
}else{
isChecked = true
self.setImage(selectedImage, forState: UIControlState.Normal)
}
}
}
}
Now in the UIViewController i create a Qbutton and before i add it to the UIViewController view i read the last state of the variable "isBtnChecked".
From the official docs:
If a boolean value is associated with defaultName in the user defaults, that value is returned. Otherwise, NO is returned.
import UIKit
class ViewController: UIViewController {
var myButton: Qbutton!
override func viewDidLoad() {
super.viewDidLoad()
myButton = Qbutton(frame: CGRectMake(100,100,50 ,50));
var isChecked = NSUserDefaults.standardUserDefaults().boolForKey("isBtnChecked") // here we obtain the last state of the button
myButton.isChecked = isChecked // we set the value
self.view.addSubview(myButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
UPDATE 2
Here is an example using the selected property of UIButton
import Foundation
import UIKit
class Qbutton: UIButton {
// Images
let selectedImage = UIImage(named: "Selected")
let unselectedImage = UIImage(named: "Unselected")
//Bool Property
override var selected: Bool{
didSet{
if selected {
self.setImage(selectedImage, forState: UIControlState.Normal)
}else{
self.setImage(unselectedImage, forState: UIControlState.Normal)
}
NSUserDefaults.standardUserDefaults().setObject(selected, forKey: "isBtnChecked")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
override init(frame: CGRect){
super.init(frame:frame)
self.layer.masksToBounds = true
self.setImage(unselectedImage, forState: UIControlState.Normal)
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func buttonClicked(sender: UIButton) {
self.selected = !self.selected
}
}
And the UIViewController :
import UIKit
class ViewController: UIViewController {
var myButton: Qbutton!
override func viewDidLoad() {
super.viewDidLoad()
myButton = Qbutton(frame: CGRectMake(100,100,50 ,50));
myButton.selected = NSUserDefaults.standardUserDefaults().boolForKey("isBtnChecked") // here we obtain the last state of the button
self.view.addSubview(myButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I hope this really can help you!
I think you are completely over-thinking it and making it complicated. Since it's just a simple button the easiest way to do it is set a bool through an IBAction. Let me know if I'm missing something from your question though.
In Objective-C it would be something like this..
{
BOOL _isStateEnabled;
}
-(IBAction)clickedButton: (id)sender {
_isStateEnabled = !_isStateEnabled;
}
In Swift I'm not fluent but, something like this..
{
let _isStateEnabled as boolean;
}
func buttonClicked(sender: UIButton) {
_isStateEnabled = !_isStateEnabled;
}

How to create radio buttons and checkbox in swift (iOS)?

I am developing an app that allows to do survey. My layout is generated from XML based questions.
I need to create radio buttons (single choice) and checkboxes (multiple answers). I did not find anything useful for swift.
Does anyone have an idea?
Checkbox
You can create your own CheckBox control extending UIButton with 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
}
}
}
And then add it to your views with Interface Builder:
Radio Buttons
Radio Buttons can be solved in a similar way.
For example, the classic gender selection 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
}
}
}
}
You can init your radio buttons like this:
override func awakeFromNib() {
self.view.layoutIfNeeded()
womanRadioButton.selected = true
manRadioButton.selected = false
}
override func viewDidLoad() {
womanRadioButton?.alternateButton = [manRadioButton!]
manRadioButton?.alternateButton = [womanRadioButton!]
}
For Radio Buttons and CheckBoxes there is nothing that comes built in.
You can implement Checkboxes easily yourself. You can set an uncheckedImage for your button for UIControlStateNormal and a checkedImage for your UIControlStateSelected. Now on tap, the button will change its image and alternate between checked and unchecked image.
To use radio buttons, you have to keep an Array for all the buttons that you want to behave as radio buttons. Whenever a button is pressed, you need to uncheck all other buttons in the array.
For radio buttons you can use SSRadioButtonsController
You can create a controller object and add buttons array to it like
var radioButtonController = SSRadioButtonsController()
radioButtonController.setButtonsArray([button1!,button2!,button3!])
The main principle is something like this here.
Swift 5, Checkbox with animation
NOTE:- if you want to remove the blue background while isSelected change the UIButton type from System to Custom
Check my Example for the Checkbox and Radio button
https://github.com/rashidlatif55/CheckBoxAndRadioButton
Create an outlet for the button
#IBOutlet weak var checkBoxOutlet:UIButton!{
didSet{
checkBoxOutlet.setImage(UIImage(named:"unchecked"), for: .normal)
checkBoxOutlet.setImage(UIImage(named:"checked"), for: .selected)
}
}
Create an extension of 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.85, y: 0.85)
}) { (success) in
UIView.animate(withDuration: 0.1, delay: 0, options: .curveLinear, animations: {
self.isSelected = !self.isSelected
//to-do
closure()
image.transform = .identity
}, completion: nil)
}
}
}
How to use
#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)
}
}
Check out DLRadioButton. You can add and customize radio buttons directly from the Interface Builder. Also works with Swift perfectly.
Update: version 1.3.2 added square buttons, also improved performance.
Update: version 1.4.4 added multiple selection option, can be used as checkbox as well.
Update: version 1.4.7 added RTL language support.
Solution for Radio Button in Swift 4.2 without using third-party libraries
Create RadioButtonController.swift file and place following code in it:
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
}
}
}
}
Use it as below in your view controller file:
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)
}
}
Be sure to add radio_off and radio_on images in Assets.
Result:
There's a really great library out there you can use for this (you can actually use this in place of UISwitch): https://github.com/Boris-Em/BEMCheckBox
Setup is easy:
BEMCheckBox *myCheckBox = [[BEMCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[self.view addSubview:myCheckBox];
It provides for circle and square type checkboxes
And it also does animations:
shorter ios swift 4 version:
#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
}
A very simple checkbox control.
#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;
}
}
For a checkbox, you don't need to subclass the UIButton. It already has the isSelected property to handle this.
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)
Then in the action method toggle it's isSelected state.
#objc func toggleCheckboxSelection() {
checkbox.isSelected = !checkbox.isSelected
}
Steps to Create Radio Button
BasicStep : take Two Button. set image for both like selected and unselected.
than add action to both button.
now start code
1)Create variable :
var btnTag : Int = 0
2)In ViewDidLoad Define :
btnTag = btnSelected.tag
3)Now In Selected Tap Action :
#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)Do code for 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
}
}
Radio Button is Ready for you
You can simply subclass UIButton and write your own drawing code to suit your needs. I implemented a radio button like that of android using the following code. It can be used in storyboard as well.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()
}
}
}
I made a super simple class to handle this in a Mac application I'm working on. Hopefully, this is helpful to someone
RadioButtonController Class:
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
}
}
}
}
Implementation in 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
}
}
For checkboxes there is actually a built-in solution in the form of UITableViewCell accessories. You can set up your form as a UITableView in which each cell as a selectable option and use accessoryType to set a check mark for selected items.
Here is a pseudo-code example:
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()
}
Radio buttons however do require a custom implementation, see the other answers.
The decision of checking or unchecking the checkbox button is something out of the scope of the view. View itself should only take care of drawing the elements, not deciding about the internal state of that. My suggested implementation is as follows:
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
}
}
It can be used with Interface Builder or programmatically. The usage of the view could be as the following example:
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)
}
I don't have enough reputation to comment, so I'll leave my version of Salil Dwahan's version here. Works for Swift 5, XCode 11.3.
First place your button on IB, select type "Custom" and create an outlet and an action with the Assistant Layout (Ctrl + Drag). Include the following code and it should end like this:
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)
}
}
Don't forget to add the image to Assets and change the name to match!
checkbox.isSelected is the way to check
Though some of the answers mention it rightly that we can use the Selected State to set an image for Selected state of the button, it won't work elegantly when the button has to have both image and text.
Like many, I ended by subclassing UIButton; however, added support for setting images from Interface Builder.
Below is my code:
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
}
}
}
Create 2 buttons one as "YES" and another as "NO".
Create a BOOL property Ex: isNRICitizen = false
Give same button connection to both the buttons and set a tag
(Ex: Yes button - tag 10 and No button -tag 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)
}
Swift 5.0 Updated Simple RadioButton For Swift (No Library)
First set images to button One Checked and Second Unchecked.
Then Provide 2 Outlet Of RadioButton.
#IBOutlet weak var radioMale: UIButton!
#IBOutlet weak var radioFemale: UIButton!
Create IBAction With Both Button Action in One Method.
#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)
}
}
Couldn't find an easy SwiftUI version in this thread so here is a quick component using SF symbols.
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()
}
}
}
If you use Image when change state. Try this:
var nightButtonState: Bool = false {
didSet {
nightButtonState ? autoNightButton.setBackgroundImage(UIImage(named: "unchecked_icon"), for: .normal) : autoNightButton.setBackgroundImage(UIImage(named: "checked_icon"), for: .normal)
}
}
Button action:
#IBAction func autoNightButtonAction(_ sender: UIButton) {
self.nightButtonState.toggle()
}

Resources