Connecting a custom PickerView to a textfield - swift

I got a custom UIPickerView from github (https://github.com/bendodson/MonthYearPickerView-Swift") and now I'm trying to connect it to a textfield with no luck. I managed to do it with the standard UiDatePicker using .addTarget and .valueChanged methods, but with this custom one addTarget throws an error. Now I only manage to get the textfield's inputView to the custom PickerView, but not save the input using my "Done" button that I created. What is it that I'm missing?
lazy var ExpireDatetextfeild: UITextField = {
let tf = LeftPaddedTextFeild()
tf.placeholder = "MM/YY"
tf.translatesAutoresizingMaskIntoConstraints = false
tf.addTarget(self, action: #selector(textfeildediting), for: .editingDidBegin)
return tf
}()
let DatePickerView: MonthYearPickerView = MonthYearPickerView()
func textfeildediting() {
let DatePickerView: MonthYearPickerView = MonthYearPickerView()
DatePickerView.backgroundColor = .white
let toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.default
toolBar.isTranslucent = true
toolBar.backgroundColor = UIColor.white
toolBar.sizeToFit()
let donebutton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(DoneFunc))
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(cancelFunc))
toolBar.setItems([cancelButton, spaceButton, donebutton], animated: false)
toolBar.isUserInteractionEnabled = true
ExpireDatetextfeild.inputAccessoryView = toolBar
ExpireDatetextfeild.inputView = DatePickerView
}
func cancelFunc(sender: UIBarButtonItem) {
DatePickerView.isHidden = true
print("DatePickerPrint")
}
func DoneFunc(sender: UIBarButtonItem) {
DatePickerView.onDateSelected = { (month: Int, year:Int) in
let Yearstring = String(format: "%02d/%d", month, year)
print(Yearstring)
}
}

Related

NavBar Button doesn't work when being clicked

I'm trying to implement a button to my navbar which should call the function addTap.
Unfortunately though, when I click the add button in the simulator, nothing happens. I put a print statement in the addTap function but I doesn't get called, meaning the function never gets called.
Have any ideas?
class ViewController: UIViewController {
var names : [String] = []
let TableView = UITableView() // view
var addButton: UIBarButtonItem = UIBarButtonItem(title: "Add", style: .done, target: self, action: #selector(addTap))
override func loadView() {
super.loadView()
setupComponents()
setupTableView()
}
func setupComponents() {
self.title = "Core Data"
self.navigationItem.rightBarButtonItem = self.addButton
}
func setupTableView() {
view.addSubview(TableView)
TableView.translatesAutoresizingMaskIntoConstraints = false
TableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
TableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
TableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
TableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
}
#objc func addTap() {
print("reached")
let alert = UIAlertController(title: "New Friend", message: "Add the name of your friend", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Add Now", style: .default) { [unowned self] action in
guard let textField = alert.textFields?.first, let nameToSave = textField.text else { return }
self.names.append(nameToSave)
self.TableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
}
Your issue is with the construction of your UIBarButtonItem. You are trying to access self before self exists.
If you construct it like this you will find that it works.
func setupComponents() {
self.title = "Core Data"
let addButton: UIBarButtonItem = UIBarButtonItem(title: "Add", style: .done, target: self, action: #selector(addTap))
self.navigationItem.rightBarButtonItem = addButton
}
Or if you need access to the button instance you can create the UIBarButtonItem lazily and replace the declaration in your class with the following:
lazy var addButton: UIBarButtonItem = {
UIBarButtonItem(title: "Add", style: .done, target: self, action: #selector(addTap))
}()

implementing toolbar fo my UITextField in UITableViewCell using protocols in swift

How to implement this code inside a Protocol in order to achieve Protocol Oriented Programing? One big problem is settling the #objc method, which are not allowed in protocols. Second one is this code is now used for UITextField inside many cells, that's why I extend UIView and why I corrected endediting
original code found here
//used inside a cell with a UITextField
extension UIView {
func toolBar() -> UIToolbar{
let toolBar = UIToolbar()
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.barTintColor = UIColor.init(red: 0/255, green: 25/255, blue: 61/255, alpha: 1)
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let buttonTitle = "Done"
let cancelButtonTitle = "Cancel"
let doneButton = UIBarButtonItem(title: buttonTitle, style: .done, target: self, action: #selector(onClickDoneButton))
let cancelButton = UIBarButtonItem(title: cancelButtonTitle, style: .plain, target: self, action: #selector(onClickCancelButton))
doneButton.tintColor = .white
cancelButton.tintColor = .white
toolBar.setItems([cancelButton, space, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
toolBar.sizeToFit()
return toolBar
}
#objc func onClickDoneButton(){
// view.endEditing(true)
self.endEditing(true)
}
#objc func onClickCancelButton(){
// view.endEditing(true)
self.endEditing(true)
}
}
EDIT on Sandeep Bhandari's answer this is the working implementation
first I added a file with
extension UIView: ToolBarProtocol {}
then inside my cell now I have:
let selDone = #selector(onClickDoneButton)
let selCancel = #selector(onClickCancelButton)
self.cellTextfield.inputAccessoryView = toolBar(with: selDone, cancelSeclector: selCancel)
#objc func onClickDoneButton() {
self.endEditing(true)
}
#objc func onClickCancelButton() {
self.endEditing(true)
}
Best you can do I guess is
protocol ToolBarProtocol where Self: UIView {
func toolBar(with doneSelector: Selector?, cancelSeclector: Selector?) -> UIToolbar
}
extension ToolBarProtocol {
func toolBar(with doneSelector: Selector?, cancelSeclector: Selector?) -> UIToolbar{
let toolBar = UIToolbar()
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.barTintColor = UIColor.init(red: 0/255, green: 25/255, blue: 61/255, alpha: 1)
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let buttonTitle = "Done"
let cancelButtonTitle = "Cancel"
let doneButton = UIBarButtonItem(title: buttonTitle, style: .done, target: self, action: doneSelector)
let cancelButton = UIBarButtonItem(title: cancelButtonTitle, style: .plain, target: self, action: cancelSeclector)
doneButton.tintColor = .white
cancelButton.tintColor = .white
toolBar.setItems([cancelButton, space, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
toolBar.sizeToFit()
return toolBar
}
}
In nutshell You can't provide a default extension to #objc protocol.
What does it have to do with this problem?
You cant provide a default extension to your done and cancel button selectors, because they will need to be annotated with #objc (Typical selector signature is selector(#objc method)) and as soon as you add #objc to them then compiler will give you a compilation error
#objc can only be used with members of classes, #objc protocols, and
concrete extension of classes
so to make your protocol compatible with #objc function you will endup making it #objc protocol, and if you make a protocol #objc you cant provide a default extension to that
For more details refer: Swift protocol extension in Objective-C class

UIDatePicker in UIViewController is showing error

I am trying to link UIDatePicker to a text field so that if I select a particular date, it gets in the textField. I am getting errors
import UIKit
class tiViewController: UIViewController {
#IBOutlet weak var txtDatePicker: UITextField!
let datePicker = UIDatePicker()
override func viewDidLoad() {
super.viewDidLoad()
showDatePicker()
}
func showDatePicker(){
//Formate Date
datePicker.datePickerMode = .date /* ERROR 1
- Value of type 'UIDatePicker' has no member 'datePickerMode'*/
//ToolBar
let toolbar = UIToolbar();
toolbar.sizeToFit()
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(donedatePicker));
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelDatePicker));
toolbar.setItems([doneButton,spaceButton,cancelButton], animated: false)
txtDatePicker.inputAccessoryView = toolbar
txtDatePicker.inputView = datePicker
}
#objc func donedatePicker(){
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
txtDatePicker.text = formatter.string(from: datePicker.date)
self.view.endEditing(true)
}
#objc func cancelDatePicker(){
self.view.endEditing(true) /* ERROR 2 - Value of type 'UIDatePicker' has no member 'date'*/
}
it shows above ERROR1 AND ERROR2
I have also linked tiviewcontroller to textfield outlet properly -

Add action to UIBarButtonItem dynamically Swift 4

let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(buttonClicked(sender:)))
#objc func buttonClicked(sender: UIBarButtonItem) {
print("Hello")
}
That's the code for my UIBarButton but when I click on it it doesn't print "Hello", what could be the problem?
EDIT: Here are my viewcontroller
It simply control a button that when it's clicked show the spinner with its control, but as I said before the button on toolbar doesn't work
class FilterViewController: UIViewController {
var search: Search?
let categoriesSpinnerDelegate = CategoriesPickerDelegate()
#IBOutlet weak var generalSpinner: UIPickerView!
#IBOutlet weak var categoriesButton: UIButton!
#IBOutlet weak var categoryRow: UIView!
var doneButton: UIBarButtonItem?
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.topViewController?.title = "Filtri"
// Set border and click action
self.categoryRow.layer.borderWidth = 1
self.categoryRow.layer.borderColor = Raccoltacase.lightGray.cgColor
self.categoryRow.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.buttonClicked(sender:))))
// Create toolbar and attach it to pickerView
let toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.default
toolBar.isTranslucent = true
//toolBar.tintColor = UIColor(red: 76/255, green: 217/255, blue: 100/255, alpha: 1)
toolBar.sizeToFit()
self.doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(buttonClicked(sender:)))
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: nil)
toolBar.setItems([cancelButton, spaceButton, doneButton!], animated: false)
toolBar.isUserInteractionEnabled = true
generalSpinner.addSubview(toolBar)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func categoriesButtonClick(_ sender: UIButton) {
self.generalSpinner.showsSelectionIndicator = true
self.generalSpinner.dataSource = categoriesSpinnerDelegate
self.generalSpinner.delegate = categoriesSpinnerDelegate
self.generalSpinner.isHidden = false
}
#objc func buttonClicked(sender: UIBarButtonItem) {
print("Hello")
}
}
Screen
Assuming that you are showing the picker sometimes (and dismissing it when user presses the done button), here is my solution:
Add a UITextField to the view in storyboard (and make the tintColor transparent (clearColor))
Add the UIToolbar as inputAccessoryView to the UITextField
Add the UIPickerView as inputView to the toolbar (Also see the note below)
Below is a sample code:
override func viewDidLoad() {
super.viewDidLoad()
textField.inputView = generalSpinner
textField.inputAccessoryView = getToolbar()
}
func getToolbar() -> UIToolbar {
let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 40))
toolBar.barStyle = UIBarStyle.default
toolBar.isTranslucent = true
self.doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(buttonClicked(sender:)))
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: nil)
toolBar.setItems([cancelButton, spaceButton, doneButton!], animated: false)
toolBar.isUserInteractionEnabled = true
return toolBar
}
Note: In case the UIPickerView is already in the storyboard (or a subview of another view), make sure to remove it in the first line of viewDidLoad (as shown below):
override func viewDidLoad() {
super.viewDidLoad()
generalSpinner.removeFromSuperview()
textField.inputView = generalSpinner
textField.inputAccessoryView = getToolbar()
}
SOLVED
When i use pickerView.addSubView(toolbar) the toolbar was placed behind the pickerview and so it was no clickable. I solved it adding the toolbar manually from storyboard with General Spinner.top = Picker Toolbar.bottom

changing textbox input view from pickerview to key pad in swift 3.0

on textbox click pickerview should raise.in picker view i had added tool like this
picker.delegate = self
picker.dataSource = self
picker.showsSelectionIndicator = true
let toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.default
toolBar.isTranslucent = true
toolBar.tintColor = UIColor.black
//UIColor(red: 76/255, green: 217/255, blue: 100/255, alpha: 1)
toolBar.sizeToFit()
let addbutton = UIBarButtonItem(title: "+Add", style: UIBarButtonItemStyle.plain, target: self, action: #selector(GBEDasboardViewController.addproducts))
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(GBEDasboardViewController.addproducts))
toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
productname.inputView = picker
productname.inputAccessoryView = toolBar
on click addbutton pickerview should close and keypad should raise
func addproducts(){
self.view.endEditing(true)
}
pickerview is closing properly but how to raise the keypad.
you should replace your code with following.
let addbutton = UIBarButtonItem(title: "+Add", style: UIBarButtonItemStyle.plain, target: self, action: #selector(GBEDasboardViewController.addProducts))
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(GBEDasboardViewController.endEditing))
func addProducts(){
self.view.endEditing(true)
productname.inputView = nil
productname.becomeFirstResponder()
}
func endEditing() {
self.view.endEditing(true)
}