Replace iOS7 Keyboard by a Date Picker in TableViewController

KevLaBoomQc picture KevLaBoomQc · Apr 22, 2014 · Viewed 8.6k times · Source

I would like my textfield "DateText" to open a DatePicker (Year - Month - Day) with this type of value:

YYYY-MM-DD

Is there an easy way to change the keyboard?

Answer

Chris picture Chris · Apr 22, 2014

You can "replace" the keyboard by using the inputView property of the UITextField:

- (void) initializeTextFieldInputView {
    UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectZero];
    datePicker.datePickerMode = UIDatePickerModeDate;
    [datePicker addTarget:self
                   action:@selector(dateUpdated:)
         forControlEvents:UIControlEventValueChanged];
    self.textField.inputView = datePicker;
}

- (void) dateUpdated:(UIDatePicker *)datePicker {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM-dd"];
    self.textField.text = [formatter stringFromDate:datePicker.date];
}

UIDatePickers do not have a delegate like UIPickerViews so that is why an action must be added as if it were a UIButton. The : at the end of the selector declaration provides the UIDatePicker as a convenience to get the date when it has been changed. If you do not want to send an object in the method, you can get the UIDatePicker by referencing the UITextField's inputView:

UIDatePicker *datePicker = (UIDatePicker *)self.textField.inputView;

Lastly, when setting formats using NSDateFormatter, is good practice to create one method to return an NSDateFormatter object to make sure the format is consistent. At the very least, create a constant/macro once in your project that declares the format string.

EDIT

As asked by Pavan in the comments thread, if you want to add a done button above your keyboard, use the inputAccessoryView:

UIToolbar *toolbar = [[UIToolbar alloc] init];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneButtonWasPressed:)];
UIBarButtonItem *flexibleSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
toolbar.items = @[flexibleSeparator, doneButton];
self.textField.inputAccessoryView = toolbar;

EDIT 2, SWIFT

Seems like this Answer is quite outdated. Adding the implementation with Swift 3:

@IBOutlet weak var textField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()
    self.initializeTextFieldInputView()
}

func initializeTextFieldInputView() {
    // Add date picker
    let datePicker = UIDatePicker()
    datePicker.datePickerMode = .date
    datePicker.addTarget(self, action: #selector(dateChanged(_:)), for: .valueChanged)
    self.textField.inputView = datePicker

    // Add toolbar with done button on the right
    let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 1))
    let flexibleSeparator = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonPressed(_:)))
    toolbar.items = [flexibleSeparator, doneButton]
    self.textField.inputAccessoryView = toolbar
}

func dateChanged(_ datePicker: UIDatePicker) {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    self.textField.text = formatter.string(from: datePicker.date)
}

You can also get the UIDatePicker by casting inputView in UITextField:

let datePicker = self.textField.inputView as? UIDatePicker