MrHappyAsthma
MrHappyAsthma

Reputation: 6522

iPhone display date picker on UITextField touch

I followed this thread: datepicker by clicking on textfield

I imported both of the following protocols:

@interface ViewController : UIViewController<UIActionSheetDelegate, UITextFieldDelegate> {

Then, in the implementation, I use the following:

- (void)viewDidLoad {

    textField.delegate = self;

[super viewDidLoad] }

Lastly, I put the actual code to display the date picker (from the thread). I also linked it all up in the IB.

    //Date Picker
- (void)textFieldDidBeginEditing:(UITextField *)aTextField{    
    [aTextField resignFirstResponder];  

    pickerViewPopup = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];  

    UIDatePicker *pickerView = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 44, 0, 0)];  
    pickerView.datePickerMode = UIDatePickerModeDate;  
    pickerView.hidden = NO;  
    pickerView.date = [NSDate date];  

    UIToolbar *pickerToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];  
    pickerToolbar.barStyle = UIBarStyleBlackOpaque;  
    [pickerToolbar sizeToFit];  

    NSMutableArray *barItems = [[NSMutableArray alloc] init];  

    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];  
    [barItems addObject:flexSpace];  

    UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneButtonPressed:)];  
    [barItems addObject:doneBtn];  

    UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelButtonPressed:)];  
    [barItems addObject:cancelBtn];  

    [pickerToolbar setItems:barItems animated:YES];  

    [pickerViewPopup addSubview:pickerToolbar];  
    [pickerViewPopup addSubview:pickerView];  
    [pickerViewPopup showInView:self.view];  
    [pickerViewPopup setBounds:CGRectMake(0,0,320, 464)];    
}  

-(void)doneButtonPressed:(id)sender{  
    //Do something here here with the value selected using [pickerView date] to get that value  
        [pickerViewPopup dismissWithClickedButtonIndex:1 animated:YES];  
}  

-(void)cancelButtonPressed:(id)sender{  
    [pickerViewPopup dismissWithClickedButtonIndex:1 animated:YES];  
}  

However, when I click on the UITextField, I get this:

enter image description here

What am I doing wrong?

Upvotes: 28

Views: 74200

Answers (9)

jane doe
jane doe

Reputation: 1

    func showDatePicker(){
    datepicker.datePickerMode = .date
    let toolBar = UIToolbar()
    toolBar.sizeToFit()
    let doneBtn = UIBarButtonItem(title: "Done", style: .plain , target: self, action: #selector(donedatePicker))
    let spaceBtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
    let cancelBtn = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelDatePicker));
    toolBar.setItems([doneBtn,spaceBtn,cancelBtn], animated: false)
    dobTextfield.inputAccessoryView = toolBar
    dobTextfield.inputView = datepicker
}
@objc func donedatePicker(){
    let formatter = DateFormatter()
    formatter.dateFormat = "mm-dd-yyyy"
    dobTextfield.text = formatter.string(from: datepicker.date)
    self.view.endEditing(true)
    
}
@objc func cancelDatePicker(){
    self.view.endEditing(true)

Upvotes: -1

tomidelucca
tomidelucca

Reputation: 2543

You could use the UITextField input view property. Just alloc init a regular UIDatePicker in code and assign it to the textfield's inputView. Doing this, the UIPickerView will be presented instead of the keyboard. If you need any code feel free to ask :)

EDIT: code

You fist hook up your textField with IB

@interface myViewController <UITextFieldDelegate>
@property (nonatomic,weak) IBOutlet UITextField *myTextField;
@end 

In the implementation

UIDatePicker *datePicker = [[UIDatePicker alloc]init];
[datePicker setDate:[NSDate date]];
[datePicker addTarget:self action:@selector(updateTextField:) forControlEvents:UIControlEventValueChanged];
if (@available(iOS 13.4, *)) {
    [datePicker setPreferredDatePickerStyle:UIDatePickerStyleWheels];
}       
[self.myTextField setInputView:datePicker];

That will bring up a UIDatePicker when you tap on the textField. Note the action that I added to the datePicker.

[datePicker addTarget:self action:@selector(updateTextField:) forControlEvents:UIControlEventValueChanged];

To update the textField each time that the user scrolls in the picker, you just need to implement the updateTextField method somewhere in the viewController

-(void)updateTextField:(id)sender
{
  UIDatePicker *picker = (UIDatePicker*)self.myTextField.inputView;
  self.myTextField.text = [NSString stringWithFormat:@"%@",picker.date];
}

With this last method, every time the user rotates the picker, the textfield will update!

  • You could use a NSDateFormatter to improve the output of the string.

Upvotes: 69

Ajinkya Sonar
Ajinkya Sonar

Reputation: 38

Adding Date Picker to UITextField as Input View - Swift Code. Hope it helps everyone. :)

func addTimePickerToTimeTextFieldView() {

    timePicker = UIDatePicker()
    timePicker?.datePickerMode = .time
    timeTextField.inputView = timePicker

    timePicker?.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
    timePicker?.setValue(#colorLiteral(red: 0.03921568627, green: 0.2352941176, blue: 0.3647058824, alpha: 1), forKeyPath: "textColor")

    timePicker?.addTarget(self, action: #selector(timeSelectedByUser(_:)), for: .valueChanged)

    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(viewTapped(_:)))
    view.addGestureRecognizer(tapGesture)

}

@objc func timeSelectedByUser(_ sender: UIDatePicker) {

    let formatter = DateFormatter()
    formatter.timeStyle = .short
    timeTextField.text = formatter.string(from: sender.date)

    //Convert Time for API - 24 hours format
    apiFormatter.dateFormat = "HH:mm"
    timeForApi = apiFormatter.string(from: sender.date)

}

Upvotes: 0

Maybelle Pacate
Maybelle Pacate

Reputation: 511

Here's what I did in Swift 4:

let datePicker = UIDatePicker()
@IBOutlet weak var myTextField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()
    setDatePicker()
}

func setDatePicker() {
    //Format Date
    datePicker.datePickerMode = .date

    //ToolBar
    let toolbar = UIToolbar();
    toolbar.sizeToFit()
    let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneDatePicker));
    let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
    let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelDatePicker));

    toolbar.setItems([doneButton,spaceButton,cancelButton], animated: false)

    myTextField.inputAccessoryView = toolbar
    myTextField.inputView = datePicker
}

@objc func doneDatePicker(){
    let formatter = DateFormatter()
    formatter.dateFormat = "MM/dd/yyyy"
    myTextField.text = formatter.string(from: datePicker.date)
    self.view.endEditing(true)
}

@objc func cancelDatePicker(){
    self.view.endEditing(true)
}

Upvotes: 6

Ashish Chauhan
Ashish Chauhan

Reputation: 1376

Swift 4.2
You can achieve this by writing just one line of code using UITextField Extension.
Credit: http://www.swiftdevcenter.com/


import UIKit

extension UITextField {

    func setInputViewDatePicker(target: Any, selector: Selector) {
        // Create a UIDatePicker object and assign to inputView
        let screenWidth = UIScreen.main.bounds.width
        let datePicker = UIDatePicker(frame: CGRect(x: 0, y: 0, width: screenWidth, height: 216))//1
        datePicker.datePickerMode = .date //2
        self.inputView = datePicker //3

        // Create a toolbar and assign it to inputAccessoryView
        let toolBar = UIToolbar(frame: CGRect(x: 0.0, y: 0.0, width: screenWidth, height: 44.0)) //4
        let flexible = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) //5
        let cancel = UIBarButtonItem(title: "Cancel", style: .plain, target: nil, action: #selector(tapCancel)) // 6
        let barButton = UIBarButtonItem(title: "Done", style: .plain, target: target, action: selector) //7
        toolBar.setItems([cancel, flexible, barButton], animated: false) //8
        self.inputAccessoryView = toolBar //9

    }

    @objc func tapCancel() {
        self.resignFirstResponder()
    }

}

In your UIViewController class write below code.


class ViewController: UIViewController {

    @IBOutlet weak var myTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.myTextField.setInputViewDatePicker(target: self, selector: #selector(tapDone(sender:datePicker1:))) //1
    }

    //2
    @objc func tapDone(sender: Any, datePicker1: UIDatePicker) {
        print(datePicker1)
        if let datePicker = self.myTextField.inputView as? UIDatePicker { // 2.1
            let dateformatter = DateFormatter() // 2.2
            dateformatter.dateStyle = .medium // 2.3
            self.myTextField.text = dateformatter.string(from: datePicker.date) //2.4
        }
        self.myTextField.resignFirstResponder() // 2.5
    }

}

For more detail visit: http://www.swiftdevcenter.com/uidatepicker-as-input-view-to-uitextfield-swift/

Upvotes: 4

HixField
HixField

Reputation: 3776

A nice approach is to make your own class (I called it TextFieldFormDate) that is derived from UITextField and encapsulates all the required behaviour. In your storyboard you then set the class for the text field to TextFieldFormDate (in my case).

Use didChange and didSelect in your ViewController (that is using the TextFieldFormDate) to be notified of changes and when date is actually picked.

class TextFieldFormDate: UITextField {

    var date : Date {
        set {
           picker.date = newValue
           text = newValue.localizedDateOnly()
        }

        get {
            return picker.date
        }
    }

    //public handlers
    var didChange : ( (Date)->() )?
    var didSelect : ( (Date)->() )?

    private var picker : UIDatePicker {
        return inputView as! UIDatePicker
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        setup()
    }

    private func setup() {
        font = UIFont.defaultFont()
        //picker for datefield
        inputView = UIDatePicker(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
        picker.datePickerMode = .date
        picker.addTarget(self, action: #selector(pickerChanged), for: .valueChanged)
        let toolBar = UIToolbar()
        toolBar.tintColor = PaintCode.mainBlue
        toolBar.items = [
            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
            BarBtnPaintCode(type: "done", target: self, action: #selector(didPressDone))
        ]
        toolBar.sizeToFit()
        inputAccessoryView = toolBar
    }

    @objc private func pickerChanged() {
        text = date.localizedDateOnly()
        didChange?(picker.date)
    }

    @objc private func didPressDone() {
        text = date.localizedDateOnly()
        resignFirstResponder()
        didSelect?(picker.date)
    }

}

Upvotes: 0

Natalia Terlecka
Natalia Terlecka

Reputation: 89

@JRo solution works great!

Here is my updated code in Swift 3:

func textFieldDidBeginEditing(_ textField: UITextField) {
    self.activeTextField = textField

    // Create a date picker for the date field.
    let picker = UIDatePicker()
    picker.datePickerMode = .date
    picker.addTarget(self, action: #selector(updateDateField(sender:)), for: .valueChanged)

    // If the date field has focus, display a date picker instead of keyboard.
    // Set the text to the date currently displayed by the picker.
    textField.inputView = picker
    textField.text = formatDateForDisplay(date: picker.date)
}


// Called when the date picker changes.

func updateDateField(sender: UIDatePicker) {
    activeTextField?.text = formatDateForDisplay(date: sender.date)
}


// Formats the date chosen with the date picker.

fileprivate func formatDateForDisplay(date: Date) -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "dd MMM yyyy"
    return formatter.string(from: date)
}

Upvotes: 4

User558
User558

Reputation: 1175

Please go through this Process In .h file create object for UIDatePicker

UIDatePicker *datePicker;

in .m file viewDidloadMethod

datePicker = [[UIDatePicker alloc]init];
datePicker.datePickerMode = UIDatePickerModeDate;
datePicker.minimumDate = [NSDate date];
[_dateTxtFld setInputView:datePicker];
UIToolbar *toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
[toolBar setTintColor:[UIColor grayColor]];
UIBarButtonItem *doneBtn=[[UIBarButtonItem alloc]initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(showSelectedDate)];
UIBarButtonItem *space=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[toolBar setItems:[NSArray arrayWithObjects:space,doneBtn, nil]];

[_dateTxtFld setInputAccessoryView:toolBar];

after that you can create ShowSele

-(void)showSelectedDate {
    if ([_dateTxtFld isFirstResponder]) {
        NSDateFormatter *formatter=[[NSDateFormatter alloc]init];
        [formatter setDateFormat:@"YYYY-MM-dd"];
        _dateTxtFld.text=[NSString stringWithFormat:@"%@",[formatter stringFromDate:datePicker.date]];
       [_dateTxtFld resignFirstResponder];
    }
   else if ([_timeTxtFld isFirstResponder]) {
   }
}

It's works for me.

Upvotes: 0

JRo
JRo

Reputation: 163

Below is how I am displaying the date picker.

- (void)textFieldDidBeginEditing:(UITextField *)textField
{


    self.activeTextField = textField;

    // Create a date picker for the date field.
    UIDatePicker *datePicker = [[UIDatePicker alloc]init];
    datePicker.datePickerMode = UIDatePickerModeDate;
    datePicker.minimumDate = [NSDate dateWithTimeIntervalSinceNow:-31536000];
    [datePicker setDate:[NSDate date]];
    [datePicker addTarget:self action:@selector(updateDateField:) forControlEvents:UIControlEventValueChanged];

    // If the date field has focus, display a date picker instead of keyboard.
    // Set the text to the date currently displayed by the picker.
    if (textField.tag == 1)
    {
    self.date.inputView = datePicker;
    self.date.text = [self formatDate:datePicker.date];
    }   
}


// Called when the date picker changes.
- (void)updateDateField:(id)sender
{
    UIDatePicker *picker = (UIDatePicker*)self.date.inputView;
    self.date.text = [self formatDate:picker.date];
}


// Formats the date chosen with the date picker.
- (NSString *)formatDate:(NSDate *)date
{
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateStyle:NSDateFormatterShortStyle];
    [dateFormatter setDateFormat:@"MM'/'dd'/'yyyy"];
    NSString *formattedDate = [dateFormatter stringFromDate:date];
    return formattedDate;
}

Upvotes: 12

Related Questions