Table View Cells are not reaching to same array - ios

I am trying to build an app which has object of Items and a controller for it which is called ItemsController. Also on my screen I suppose to have a table view and a button on it. The functionality of button is when it is clicked it needs to check favoriteItems array in ItemsController if it is found in that array remove element, if it isn't found there then append it to array. Operations for remove and append good but unfortunately all cells are not working together. They creates their own favoriteItems array.
To achieve this I tried to make ItemsController to be a singleton. I changed class to a struct and called ItemsController.sharedInstance everywhere. It actually solved a lot of my problem and I believe that the source I learnt this is not wrong about it. But why my tableview cells doesn't use ItemsController's favoriteItems array instead create theirs?
struct ItemsController {
var favoriteItems = [Items]()
static var sharedInstance = ItemsController()
init(){
itemsArray = [...items...]
}
}
class TableViewCell: UITableViewCell {
#IBOutlet weak var favoriteButton: UIButton!
let buttonFirstColor : UIColor = UIColor.clear
let buttonSecondColor : UIColor = UIColor(red: 224/255.0, green: 74/255.0, blue: 94/255.0, alpha: 1.0)
var itemsController = ItemsController.sharedInstance
var itemDedicated = Items(name: "", pic: "", aciklama: "")
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
favoriteButton.layer.cornerRadius = 0.5 * favoriteButton.bounds.size.width
favoriteButton.backgroundColor = UIColor.clear
favoriteButton.layer.borderColor = UIColor(red: 224/255.0, green: 74/255.0, blue: 94/255.0, alpha: 1.0).cgColor
favoriteButton.layer.borderWidth = 4.0
favoriteButton.clipsToBounds = true
setFavoriteButton()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func favoriteButtonClicked(_ sender: Any) {
var favoriteFound = false
for items in itemsController.favoriteItems{
if(items.name == itemDedicated.name){
favoriteFound = true }
}
if(favoriteFound){
itemsController.favoriteItems.remove(at: itemsController.favoriteItems.index(of: itemDedicated)!)
} else {
itemsController.favoriteItems.append(itemDedicated)
}
setFavoriteButton()
}
private func setFavoriteButton(){
var favoriteFound = false
for items in itemsController.favoriteItems{
if(items.name == itemDedicated.name){
favoriteFound = true }
}
if(favoriteFound){
favoriteButton.backgroundColor = buttonSecondColor
favoriteButton.setTitleColor(buttonFirstColor, for: .normal)
} else {
favoriteButton.backgroundColor = buttonFirstColor
favoriteButton.setTitleColor(buttonFirstColor, for: .normal)
}
}
}

Related

Follow and unfollowing button issue while closing & reopening the app

In the Tab Bar Controller here are four tabs namely home, discover, notification and user profile. The discover tab controller lists all the users in Firebase. The users are listed with username and follow button. If the current user taps on follow, the title is set to following.
protocol PeopleTableViewCellDelegate {
func goToProfileUserVC(userId: String)
}
#IBOutlet weak var profileImage: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var followButton: UIButton!
var delegate: PeopleTableViewCellDelegate?
var user: User? {
didSet {
updateView()
}
}
func updateView() {
nameLabel.text = user?.username
if let photoUrlString = user?.profileImageUrl {
let photoUrl = URL(string: photoUrlString)
profileImage.sd_setImage(with: photoUrl, placeholderImage: UIImage(named: "placeholderImg"))
}
if user!.isFollowing! {
configureUnFollowButton()
} else {
configureFollowButton()
}
}
func configureFollowButton() {
followButton.layer.borderWidth = 1
followButton.layer.borderColor = UIColor(red: 226/255, green: 228/255, blue: 232.255, alpha: 1).cgColor
followButton.layer.cornerRadius = 5
followButton.clipsToBounds = true
followButton.setTitleColor(UIColor.white, for: UIControlState.normal)
followButton.backgroundColor = UIColor(red: 69/255, green: 142/255, blue: 255/255, alpha: 1)
followButton.setTitle("Follow", for: UIControlState.normal)
followButton.addTarget(self, action: #selector(self.followAction), for: UIControlEvents.touchUpInside)
}
func configureUnFollowButton() {
followButton.layer.borderWidth = 1
followButton.layer.borderColor = UIColor(red: 226/255, green: 228/255, blue: 232.255, alpha: 1).cgColor
followButton.layer.cornerRadius = 5
followButton.clipsToBounds = true
followButton.setTitleColor(UIColor.black, for: UIControlState.normal)
followButton.backgroundColor = UIColor.clear
followButton.setTitle("Following", for: UIControlState.normal)
followButton.addTarget(self, action: #selector(self.unFollowAction), for: UIControlEvents.touchUpInside)
}
func followAction() {
if user!.isFollowing! == false {
Api.Follow.followAction(withUser: user!.id!)
configureUnFollowButton()
user!.isFollowing! = true
}
}
func unFollowAction() {
if user!.isFollowing! == true {
Api.Follow.unFollowAction(withUser: user!.id!)
configureFollowButton()
user!.isFollowing! = false
}
}
override func awakeFromNib() {
super.awakeFromNib()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.nameLabel_TouchUpInside))
nameLabel.addGestureRecognizer(tapGesture)
nameLabel.isUserInteractionEnabled = true
}
func nameLabel_TouchUpInside() {
if let id = user?.id {
delegate?.goToProfileUserVC(userId: id)
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Here code for duplicate user:
func loadUsers() {
// self.users = []
API.User.observeUser { (user) in
self.isFollowing(userId: user.id!, completed: { (value) in
user.isFollowing = value
self.users.append(user)
self.tableView.reloadData()
})
}
}
My issue: The list show at Discover tab is duplicated and when user taps on the follow button, it's title is set to following. But if the user closes and reopens the app, upon return to Discover tab the previously followed user's button remains follow despite the data having been inserted correctly in Firebase.
Any help much appreciated please...
I am writting this as an answer as there is (probably) not enough space to write it as a comment.
First of all your set up looks a bit messy, it seems that some details are handled locally and some on Firebase, and nothing in your code is triggering loadUsers().
I would advice you to set up as following:
Create a class named followingUsers give them the necessary properties e.g following and set your initializer. Then add var followingUsersArray = [followingUsers]() inside your ViewController.
Put the obeserve Firebase function in your viewDidLoad(), get
all the data and put it in your followingUsersArray then reload your tableView.
Create a UITableViewCell class and give it the desired properties, then set a method to configure the cell. Call that method from cellAtRow and pass it the values from the followingUsersArray.

Swift 3 - Changing background colour of all view controllers, via switch(Dark mode/Night mode)

i crated a switch that lets the user change the background colour (dark mode). This only works on the view controller that the code is linked with. How would i set it so when the switch is activated to either dark or light mode, every view controller in my application would change, not just the one. Heres my code:
import UIKit
class DarkMode: UIViewController {
#IBOutlet var DarkSwitch: UISwitch!
#IBOutlet var LightSwitch: UISwitch!
var DarkisOn = Bool()
var LightisOn = Bool()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let DarkDefault = UserDefaults.standard
DarkisOn = DarkDefault.bool(forKey: "DarkDefault")
let LightDefault = UserDefaults.standard
LightisOn = LightDefault.bool(forKey: "LightDefault")
if (DarkisOn == true) {
DarkSwitch.isOn = true
LightSwitch.isOn = false
//run dark theme
DarkTheme()
}
if (LightisOn == true) {
DarkSwitch.isOn = false
LightSwitch.isOn = true
//run light theme
LightTheme()
}
}
func DarkTheme() //dark colour
{
self.view.backgroundColor = UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1.0)
}
func LightTheme() //light colour
{
self.view.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
#IBAction func DarkAction(_ sender: Any)
{
DarkSwitch.isOn = true
LightSwitch.isOn = false
//run dark theme func
DarkTheme()
let DarkDefault = UserDefaults.standard
DarkDefault.set(true, forKey: "DarkDefault")
let LightDefault = UserDefaults.standard
LightDefault.set(false, forKey: "LightDefault")
}
#IBAction func LightAction(_ sender: Any)
{
DarkSwitch.isOn = false
LightSwitch.isOn = true
//run light theme func
LightTheme()
let DarkDefault = UserDefaults.standard
DarkDefault.set(false, forKey: "DarkDefault")
let LightDefault = UserDefaults.standard
LightDefault.set(true, forKey: "LightDefault")
}
}
You can create a base class like this (This is something I have used.)
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.barTintColor = MainColor
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]//user global variable
self.navigationController?.navigationBar.barStyle = UIBarStyle.black //user global variable
self.navigationController?.navigationBar.tintColor = UIColor.white //user global variable
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Setup all your theme here.
All the color value should be global which you can change from another ViewController.
And now declare your all ViewControllers like this
class HomeViewController: BaseViewController {
}
This way HomeViewController will have all the appearance you set in BaseViewController.
Now All you have to do is change those global variables for color value.
For one of my projects I created a class that controlled the UI colour scheme across all my ViewControllers.
class UIColourScheme {
func set(for viewController: UIViewController) {
viewController.view.backgroundColor = bgColour
...
}
var bgColour = UIColor.black
static let instance = UIColourScheme()
}
I would then call this function in viewDidLoad() for every ViewController
class MyViewController : UIViewController {
func viewDidLoad() {
...
UIColourScheme.instance.set(for:self)
}
}
My colour scheme class setup colours for everything but it could be simplified to just the background colour as above.
you can use this
protocol colorable {
func setcolor(color: UIColor)
}
class HomeVC: colorable {
}
I modified viewWillAppear method. And added dark mode based on the time of the day.
You do not need to format the time/hours you receive back you may wanna use it as is in conditional statement.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
// get time of the day
let hour = Calendar.current.component(.hour, from: Date())
print(hour)
if hour >= 14 {
overrideUserInterfaceStyle = .dark
}
else {
overrideUserInterfaceStyle = .light
}
}

How do I get the index out of the optional func didMoveToPage?

I am using uacaps/CAPSPageMenu in my app and I cannot figure out how to get the number of the active page so I can show a webpage corresponding to the page. In the code CAPSPageMenu.swift the following code is used.
import UIKit
#objc public protocol CAPSPageMenuDelegate {
// MARK: - Delegate functions
optional func willMoveToPage(controller: UIViewController, index: Int)
optional func didMoveToPage(controller: UIViewController, index: Int)
}
I think the index: Int part in the optional func didMoveToPage is giving me a number of the current page. Is this right? How do I get that index number in the ViewController.swift code?
EDIT
In CAPSPageMenu I found this code.
public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if scrollView.isEqual(controllerScrollView) {
// Call didMoveToPage delegate function
let currentController = controllerArray[currentPageIndex]
delegate?.didMoveToPage?(currentController, index: currentPageIndex)
The ViewController.swift code as shown below.
//
// ViewController.swift
// PageMenuDemoStoryboard
//
// Created by Niklas Fahl on 12/19/14.
// Copyright (c) 2014 CAPS. All rights reserved.
//
import UIKit
var websiteArray = ["http://website_0", "http://website_1", "http://website_2"]
//class ViewController: UIViewController {
class ViewController: UIViewController,CAPSPageMenuDelegate {
var pageMenu : CAPSPageMenu?
var pageNumber = 0
#IBOutlet weak var showWebsite: UIWebView!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// MARK: - UI Setup
self.title = "App Title"
self.navigationController?.navigationBar.barTintColor = UIColor(red: 30.0/255.0, green: 30.0/255.0, blue: 30.0/255.0, alpha: 1.0)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: UIBarMetrics.Default)
self.navigationController?.navigationBar.barStyle = UIBarStyle.Black
self.navigationController?.navigationBar.tintColor = UIColor.whiteColor()
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.orangeColor()]
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "<-", style: UIBarButtonItemStyle.Done, target: self, action: "didTapGoToLeft")
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "->", style: UIBarButtonItemStyle.Done, target: self, action: "didTapGoToRight")
// MARK: - Scroll menu setup
// Initialize view controllers to display and place in array
var controllerArray : [UIViewController] = []
let controller1 : TestCollectionViewController = TestCollectionViewController(nibName: "TestCollectionViewController", bundle: nil)
controller1.title = "Item_0"
controller1.photoNameArray = ["Item_0.png"]
controllerArray.append(controller1)
let controller2 : TestCollectionViewController = TestCollectionViewController(nibName: "TestCollectionViewController", bundle: nil)
controller2.title = "Item_1"
controller2.photoNameArray = ["Item_1.png"]
controllerArray.append(controller2)
let controller3 : TestCollectionViewController = TestCollectionViewController(nibName: "TestCollectionViewController", bundle: nil)
controller3.title = "Item_2"
controller3.photoNameArray = ["Item_2.png"]
controllerArray.append(controller3)
// Customize menu (Optional)
let parameters: [CAPSPageMenuOption] = [
.ScrollMenuBackgroundColor(UIColor(red: 30.0/255.0, green: 30.0/255.0, blue: 30.0/255.0, alpha: 1.0)),
.ViewBackgroundColor(UIColor(red: 20.0/255.0, green: 20.0/255.0, blue: 20.0/255.0, alpha: 1.0)),
.SelectionIndicatorColor(UIColor.orangeColor()),
.BottomMenuHairlineColor(UIColor(red: 70.0/255.0, green: 70.0/255.0, blue: 80.0/255.0, alpha: 1.0)),
.MenuItemFont(UIFont(name: "HelveticaNeue", size: 13.0)!),
.MenuHeight(30.0),
.MenuItemWidth(90.0),
.CenterMenuItems(true)
]
// Initialize scroll menu
pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: CGRectMake(0.0, self.view.frame.height * 0.71, self.view.frame.width, self.view.frame.height * 0.33), pageMenuOptions: parameters)
self.addChildViewController(pageMenu!)
self.view.addSubview(pageMenu!.view)
pageMenu!.didMoveToParentViewController(self)
pageMenu!.delegate = self
func willMoveToPage(controller: UIViewController, index: Int) {
let subview=controller as! ViewController
subview.pageNumber=index;
}
}
func didTapGoToLeft() {
var currentIndex = pageMenu!.currentPageIndex
if currentIndex > 0 {
pageMenu!.moveToPage(currentIndex - 1)
}
setWebPage()
}
func didTapGoToRight() {
var currentIndex = pageMenu!.currentPageIndex
if currentIndex < pageMenu!.controllerArray.count {
pageMenu!.moveToPage(currentIndex + 1)
}
setWebPage()
}
func setWebPage() {
var currentIndex = pageMenu!.currentPageIndex
switch currentIndex {
case 0:
let url = NSURL (string: "\(websiteArray[0])");
let requestObj = NSURLRequest(URL: url!);
showWebsite.loadRequest(requestObj);
break
case 1:
let url = NSURL (string: "\(websiteArray[1])");
let requestObj = NSURLRequest(URL: url!);
showWebsite.loadRequest(requestObj);
break
case 2:
let url = NSURL (string: "\(websiteArray[2])");
let requestObj = NSURLRequest(URL: url!);
showWebsite.loadRequest(requestObj);
break
default:
break
}
}
// MARK: - Container View Controller
override func shouldAutomaticallyForwardAppearanceMethods() -> Bool {
return true
}
override func shouldAutomaticallyForwardRotationMethods() -> Bool {
return true
}
}
When I tap the buttons it is working like it should. The navigation bar shows the active page and the picture (collectionViewController) that belongs to the active page is shown and also the webpage that belongs to the active page is shown. But I do not want to use the buttons. I want to use the collectionViewController so that when I swipe the image to the next page the new image is shown (this is working already) and the corresponding webpage also (this is not working because of not setting the pageMenu!.currentPageIndex).
How to activate the didTapGoToLeft and Right methods when I swipe the picture?
The CAPSPageMenu provides a delegate method that inform's its delegate that the page has changed. These are the delegate methods you listed in your question.
So, in your ViewController class you need to implement these delegate methods.
First, tell the compiler that your class implements the protocol:
class ViewController:UIViewController,CAPSPageMenuDelegate
Now, you need to set the view controller as the delegate. Where you create the CAPSPageMenu you will need something like this -
pageMenu.delegate=self
Finally, implement the delegate methods. The CAPSPageMenu is provided with an array of view controllers that it manages. You haven't given the precise details of these, but I am assuming that they implement some class which I am calling SubViewController. Define an integer property pageNumber in this class and then your delegate method can simply be -
func willMoveToPage(controller: UIViewController, index: Int) {
let subview=controller as! SubViewController
subview.pageNumber=index;
}
Then, in your SubViewController you can implement a setter on pageNumber that does whatever it needs to when the page number changes. In your delegate method you could also use the index to index into an array of strings (URLs say) and then set a string/URL property on the sub view controller - it depends on what you are trying to do.

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

TTTAttributedLabel Link detecting not work in iOS8 with swift

I want to use TTTAttributedLabel to detect the link of the text in the Label of UITableViewCell, but it doesn't work. I'm using swift with iOS8. below is UITableViewCell code:
class StoryTableViewCell: UITableViewCell, TTTAttributedLabelDelegate {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
// Link properties
let textLabel = self.descriptionLabel
let linkColor = UIColor(red: 0.203, green: 0.329, blue: 0.835, alpha: 1)
let linkActiveColor = UIColor.blackColor()
if (textLabel is TTTAttributedLabel) {
var label = textLabel as TTTAttributedLabel
label.linkAttributes = [NSForegroundColorAttributeName : linkColor]
label.activeLinkAttributes = [NSForegroundColorAttributeName : linkActiveColor]
label.enabledTextCheckingTypes = NSTextCheckingType.Link.toRaw()
label.delegate = self
}
}
}
I think you have not configured your custom cell correctly.
First at your customCell declare and connect your IBOutlet-s. Select your textLabel and add its class to TTTAttributedLabel. Your custom cell should look like this:
class StoryTableViewCell: UITableViewCell {
#IBOutlet weak var textLabel: TTTAttributedLabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Second you need to add the TTTAttributedLabelDelegate at the class where you are using the tableView datasource and delegate.
Then under cellForRowAtIndexPath
var cell: StoryTableViewCell = tableView.dequeueReusableCellWithIdentifier("yourCellIdentifier") as StoryTableViewCell
let linkColor = UIColor(red: 0.203, green: 0.329, blue: 0.835, alpha: 1)
let linkActiveColor = UIColor.blackColor()
cell.textLabel.delegate = self
cell.textLabel.linkAttributes = [kCTForegroundColorAttributeName : linkColor]
cell.textLabel.activeLinkAttributes = [kCTForegroundColorAttributeName : linkActiveColor]
cell.textLabel.enabledTextCheckingTypes = NSTextCheckingType.Link.rawValue
Then if you have methods that need to be executed from TTTAttributedLabelDelegate add them and do your calculations.
Hope it helps
If you've set TTTAttributedLabel as the class of your UILabel, within a nib or the storyboard, make sure User Interaction Enabled is set to true, as be default a UILabel will have user interaction disabled.
let linkColor = UIColor.blueColor()
let linkActiveColor = UIColor.greenColor()
textLabel.delegate = self
textLabel.linkAttributes = [kCTForegroundColorAttributeName : linkColor.CGColor,kCTUnderlineStyleAttributeName : NSNumber(bool: true)]
textLabel.activeLinkAttributes = [NSForegroundColorAttributeName : linkActiveColor]
textLabel.enabledTextCheckingTypes = NSTextCheckingType.Link.rawValue
swift 4.2
label.enabledTextCheckingTypes = NSTextCheckingResult.CheckingType.link.rawValue | NSTextCheckingResult.CheckingType.phoneNumber.rawValue
Nothing works for me finally i put below code in TTTAttributedLabel.m in commonInit() method
self.enabledTextCheckingTypes = NSTextCheckingTypeLink;

Resources