Date Picker Only Works After Clicking out of Text Field - swift

I have a date picker I am using to set the value of a text field. It works great except that it only works the 2nd time that I tap into the text field, that is, the first time I tap the text field it shows me the standard keyboard. Then if I tap out of the textfield and back into it, it shows the datepicker. I've tried different variations of it, but it either doesn't work at all, or I get the same problem. This is how I set it up:
class ExpDateTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
#IBAction func textFieldEditing(sender: UITextField) {
let datePickerView:UIDatePicker! = UIDatePicker()
datePickerView.datePickerMode = UIDatePickerMode.date
sender.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(ExpDateTableViewCell.datePickerValueChanged), for: UIControlEvents.valueChanged)
}
func datePickerValueChanged(sender:UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = DateFormatter.Style.medium
dateFormatter.timeStyle = DateFormatter.Style.none
textField.text = dateFormatter.string(from: sender.date)
}
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
}
}

The problem is this code:
#IBAction func textFieldEditing(sender: UITextField) {
// ...
sender.inputView = datePickerView
}
You are not setting the text field's inputView to the picker view until after the first time we have started editing. Thus we get the effect you correctly described: the second time we edit, the picker view is present.
You need to set the text field's inputView much earlier, such as in awakeFromNib, before the user has a chance to edit the text field for the first time.

First make UIDatepickerview as a inputview for textfield
Add this code inside the textfield action
#IBAction func textFieldEditing(sender: UITextField) {
let datePickerView:UIDatePicker = UIDatePicker()
datePickerView.datePickerMode = UIDatePickerMode.Date
sender.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(ViewController.datePickerValueChanged), forControlEvents: UIControlEvents.ValueChanged)
}

Related

Auto update UITextfield with data from separate UITextfield

I have three UITextfields (customerRequestTextField , fundsAvailableTextField and amountOwedMarketTextField) on the same ViewController.
I would like to set up the amountOwedTextField so that it automatically updates its field by subtracting the data entered into the other two textfields (customerRequestTextField - fundsAvailableTextField).
Should I use NSNotifications? Or a selector? Or something else?
I have tried setting up a selector, but my version does not work.
This is declared globally.
var amountOwedToMarket
This code is located in the viewDidLoad().
amountOwedMarketTextField.text = String(amountOwedToMarket)
amountOwedMarketTextField.addTarget(self, action: #selector(self.textFieldDidChange(sender:)), for: .editingChanged)
}
This is declared outside of the viewDidLoad()
#objc func textFieldDidChange(sender: UITextField) -> Int {
return Int(amountCustomerRequestTextField.text!) ?? 21
}
You need to add the target to textfields that you want to listen to their changes
// in viewDidLoad
amountCustomerRequestTextField.addTarget(self, action: #selector(self.textFieldDidChange), for: .editingChanged)
fundsAvailableTextField.addTarget(self, action: #selector(self.textFieldDidChange), for: .editingChanged)
#objc func textFieldDidChange(_ sender: UITextField) {
if let first = Int(amountCustomerRequestTextField.text!) , let second = Int(fundsAvailableTextField.text!) {
amountOwedMarketTextField.text = "\(first - second)"
}
}

How to change input textfiled [Swift]

In my swift app I've two textfields and as inputView is UIDatePicker().
Here's my code:
class ViewController: UIViewController {
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
var timePicker = UIDatePicker()
var timeString = String()
override func viewDidLoad() {
super.viewDidLoad()
timePicker.datePickerMode = .time
}
#objc func formatData(_ datePickerView: UIDatePicker) {
let timeFormatter = DateFormatter()
timeFormatter.timeStyle = .short
timeString = timeFormatter.string(from: datePickerView.date)
}
#IBAction func textFieldChanged(_ sender: UITextField) {
sender.inputView = timePicker
timePicker.addTarget(self, action: #selector(formatData(_:)), for: .valueChanged)
sender.text = timeString
}
}
By this way to change value into text field I've to deselect it and then rettapping on it the value appear.
But it's not correct.
first you take the IBAction of that textfield which you want to change the input view and name should be of your IBAction method didBeginEditing and in that method you can the input view of that textfield which you want to change

UIPickerView is not selecting the date in UITextField

I am new in swift. On executing this app login screen goes to sign in.On selecting "Already have account sign up".You get to sign up view. In the sign up trying to develop the picker view.These are two issues arise while developing picker view
1) picker view should be hidden on loading view controller .but picker view is visible as view controller appear?
2) In date of birth pickview when a done button on date picker view is selected the app crash .but it should display the corresponding date in a text field?
func showDatePicker(){
//Formate Date
datePicker.datePickerMode = .date
//ToolBar
let toolbar = UIToolbar();
toolbar.sizeToFit()
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.bordered, target: self, action: "donedatePicker")
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.bordered, target: self, action: "cancelDatePicker")
toolbar.setItems([doneButton,spaceButton,cancelButton], animated: false)
dateTextField.inputAccessoryView = toolbar
dateTextField.inputView = datePicker
}
func donedatePicker(){
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
dateTextField.text = formatter.string(from: datePicker.date)
self.view.endEditing(true)
}
func cancelDatePicker(){
self.view.endEditing(true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
pickerView.delegate=self
pickerView.dataSource=self
genderTextField.inputView=pickerView
showDatePicker()
}
How to avoid this crash. You can download the project from this link https://drive.google.com/file/d/1a6Pmw2gVDwLP9grL8tG72NBx-tKwZozI/view?usp=sharing
you miss few things in view did load I had updated the code
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate=self
pickerView.dataSource=self
genderTextField.inputView = pickerView
genderTextField.delegate = self
dateTextField.delegate = self
}
Assign the text field delegate and implement the function textFieldShouldBeginEditing function for showing the Date Picker
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField.tag == 1 { //Date Text Field
showDatePicker()
}
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
I had assigned the tag value of Date Text Field from the storyboard and hide the picker view from the storyboard. It will solve your both points
First you need to give delegate to UITextField i.e
dateTextField.delegate = self
and then you need to confirm with UITextFieldDelegate method with sign up class i.e
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == dateTextField {
self.showDatePicker()
}
}
Use this above code may it helps you.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
pickerView.delegate=self
pickerView.dataSource=self
genderTextField.inputView=pickerView
showDatePicker()
}
The mistake is here. When the view is load in viewDidLoad, date picker is show itself. So you must add a action for click to show you picker view and call it in there.
For example
#objc fileprivate func showIt(_ sender:UIButton){
showDatePicker()
}
Also your action must be set wit #selector
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.bordered, target: self, action: "donedatePicker")
changed to
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.bordered, target: self, action: #selector(donedatePicker))
And for error #1 you must be make firstResponder UITextField somehow, you must resign it.
Can you add this function for textFieldDelegate.
extension YourViewController: UITextFieldDelegate{
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField.isFirstResponder{
showDatePicker()
}
}
}
you should b calling this showDatePicker() on a tap at date textfield.
func textFieldDidBeginEditing(_ textField: UITextField) {
let datePicker = UIDatePicker()
if startDateTxt == textField{
textField.inputView = datePicker
datePicker.addTarget(self, action: #selector(showDatePicker()), for: .valueChanged)
}
}
and for 2nd error:
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.bordered, target: self, action: #selector(donedatePicker))

Open UIDatePicker when UITextField is tapped from Custom Component

I have a custom UIView component that has a UITextField, UIImageView and another UIView.
I need to change the behavior of the UITextField to display a UIDatePicker when it's tapped. This is the code I'm trying to execute but for some reason the datePicker doesn't open when it's tapped:
class TextFieldWithFeedback : UIView {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var underlineView: UIView!
override func draw(_ rect: CGRect) {
let datePicker = UIDatePicker()
datePicker.datePickerMode = .date
self.textField.inputView = datePicker
}
}
When I used the same code on my ViewController (code below) it worked:
override func viewDidLoad() {
super.viewDidLoad()
let datePicker = UIDatePicker()
datePicker.datePickerMode = .date
customView.textField.inputView = datePicker
}
Now, this solution works but it's not ideal because I have 8 of those custom views and it would be better to set it once instead of 8 times.
Which method of the View class should I use to set the datePicker up? Since draw doesn't work.
Also, how can I attach a function to modify my UITextField value when the user picks a date?
Managed to solve it like this:
//To control whether or not to use the DatePicker, easily customized on the Storyboard
#IBInspectable var useDatePicker: Bool = false
#IBAction func textFieldEditing(_ sender: UITextField) {
self.textFieldStartedEditing(sender: sender)
}
func textFieldStartedEditing(sender: UITextField) {
if useDatePicker {
let datePickerView:UIDatePicker = UIDatePicker()
datePickerView.datePickerMode = .date
sender.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(self.datePickerValueChanged), for: UIControlEvents.valueChanged)
}
}
func datePickerValueChanged(sender: UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/YYYY"
self.textField.text = dateFormatter.string(from: sender.date)
}
All of the code above inside my customView class.
If anyone else is having trouble with this and needs help feel free to comment, I promise I'll be more helpful than the people who commented on the question :)
what you need to do is addTarget to your Textfield and then in a method Show the UIPickerView
self.textField.addTarget(self, action: #selector(ViewController.openDatesPicker), for: .touchDown)
You should also set tag for your textfield so you can identify it later in the code. Also you should implement this method which stops the keyboard from showing up
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField.tag == 2 {
return true
} else {
return false
}
}

Swift datepicker in popovercontroller not updating the correct label

In my app i have added 2 labels and 2 buttons, the buttons are hooked to a function that pops a datepicker in popovercontroller, when user select a date the corresponding label should change.
Everything work except the labels are updated together, what I want is update only the relevant label, i.e. when when button1 is pressed label1 should recieve datepicker date and vice versa.
Here is my code:
import UIKit
class PopoverTestVC: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var dateLabel2: UILabel!
#IBOutlet weak var selectButton: UIButton!
#IBOutlet weak var selectButton2: UIButton!
#IBOutlet var datePicker: UIDatePicker!
var dateString = ""
let vc = UIViewController()
override func viewDidLoad() {
super.viewDidLoad()
datePicker.timeZone = NSTimeZone(abbreviation: "GMT")
//datePicker.addTarget(self, action: Selector("datePicked:"), forControlEvents: UIControlEvents.ValueChanged)
}
func datePicked(sender: UIDatePicker) {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd MMM yyyy HH:mm"
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
dateLabel.text = dateFormatter.stringFromDate(datePicker.date)
}
func datePicked2(sender: UIDatePicker) {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd MMM yyyy HH:mm"
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
dateLabel2.text = dateFormatter.stringFromDate(datePicker.date)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func popUp(sender: UIButton)
{
let fr = datePicker.frame
vc.view.frame = fr
vc.view.addSubview(datePicker!)
vc.view.backgroundColor = UIColor.greenColor()
vc.preferredContentSize = datePicker.frame.size
vc.modalPresentationStyle = UIModalPresentationStyle.Popover
if sender == selectButton
{
datePicker.addTarget(self, action: Selector("datePicked:"), forControlEvents: UIControlEvents.ValueChanged)
}
else if sender == selectButton2
{
datePicker.addTarget(self, action: Selector("datePicked2:"), forControlEvents: UIControlEvents.ValueChanged)
}
let popOverPC = vc.popoverPresentationController
vc.popoverPresentationController?.sourceRect = sender.frame
vc.popoverPresentationController?.sourceView = view
popOverPC!.permittedArrowDirections = UIPopoverArrowDirection.Any
popOverPC!.delegate = self
presentViewController(vc, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle
{
return UIModalPresentationStyle.None
}
}
Appreciate any help or suggestion to do that in better way as the app might have several outlets that use the same datepicker.
I'd move your date picker to a custom class (this also lets you use a xib to do some cool design stuff) call this from your view controller setting a var to the button that called the date picker. Create a protocol in the date picker and implement the delegate in the parent view controller populating whatever labels you require based on the button that called the date picker.
For example, in my app I have several text fields that must contain dates. When the user begins to edit the text field I launch a custom popover from textFieldShouldBeginEditing and assign the text field to a var.
The parent view controller is set as the delegate to a protocol in my custom date picker:
// MARK: - Textfield delegate
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
textField.backgroundColor = UIColor.whiteColor()
if (textField.tag == 500 || textField.tag == 501)
{
activeTextField = textField
let vc = BGSDatePickerVC(nibName: "BGSDatePickerVC", bundle: nil)
vc.modalPresentationStyle = UIModalPresentationStyle.Popover
if textField.tag == 500{
vc.popoverPresentationController?.sourceView = viewMarkerFromDate
}else
{
vc.popoverPresentationController?.sourceView = viewMarkerToDate
}
vc.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.Up
vc.preferredContentSize = CGSizeMake(vc.view.frame.width, vc.view.frame.height)
vc.delegate = self
self.presentViewController(vc, animated: true, completion: nil)
return false
}
return true
}
The protocol in my custom date picker popover:
protocol BGSDatePickerVCProtocol
{
func bgsDatePickerUse(date: NSDate, strDate: String)
}
class BGSDatePickerVC: UIViewController {
var delegate:BGSDatePickerVCProtocol! = nil
and the implementation in the calling view controller:
// MARK: - Delegates
// MARK: BGSDatePickerVCProtocol
func bgsDatePickerUse(date: NSDate, strDate: String)
{
if activeTextField.tag == 500
{
dateSelectedFrom = date
}
if activeTextField.tag == 501
{
dateSelectedTo = date
}
activeTextField.text = strDate
}