I have already researched this topic to death and found people posting the exact same question on a number of websites including right here in stackoverflow.
I have
I had the same issue using Storyboard. Here is how I resolved it:
Overview: I alloc and initialize my UIDatePicker property in viewDidLoad:. I then set the inputView property of my textfield to my datepicker property.
Here is my code: In TripViewController.h:
@property (nonatomic,strong) IBOutlet UIDatePicker *datePicker;
In TripViewController.m:
@synthesize datePicker;
...
-(void)viewDidLoad {
...
self.datePicker = [[UIDatePicker alloc]init];
[self.datePicker addTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];
self.dateField.inputView = self.datePicker;
}
I then implement my method, dateChanged so that whenever the date picker wheel stops moving, my textfield is updated.
- (void)dateChanged
{
NSDate *date = self.datePicker.date;
NSDateFormatter *dateFormat = [[NSDateFormatter alloc]init];
[dateFormat setDateStyle:NSDateFormatterMediumStyle];
self.dateField.text = [dateFormat stringFromDate:date];
}
Showing a UIDatePicker
for the inputView
of a UITextField
is relatively hard compared to showing a keyboard, but relatively easy compared to the trouble you've had.
One of the first problems I noticed with your code, and it's a very common problem with those new to iOS/Mac development, is that you are attempting to set the property of an object that doesn't exist yet. Putting "self.dueDate.inputView = datePicker;
" in your initWithNibName:bundle:
will not work because the view has not yet loaded, and dueDate
is part of your view. In objective-c an object is instantiated with alloc & init. Init is the first real method call to any object. At this point in your view controller's life the view has not been created yet. The method call where self.dueDate.inputView = datePicker;
belongs is in the viewDidLoad
method. It is called exactly when it sounds like it's called, and your dueDate
property will be properly loaded at that point. There is no need to use a custom subclass of UITextField
to display a date picking view for for your text field. Here is a very basic example of a custom input view class:
ExampleBasicDateInputView.h:
#import <UIKit/UIKit.h>
@interface ExampleBasicDateInputView : UIView
@property (strong,nonatomic) UIDatePicker *datePicker;
@end
ExampleBasicDateInputView.m:
#import "ExampleBasicDateInputView.h"
@implementation ExampleBasicDateInputView{
UITextField *_inputField; // ivar to store the textfield currently being edited
}
@synthesize datePicker = _datePicker;
// TARGET METHODS
-(void)pickerValueChanged:(UIDatePicker *)picker{
_inputField.text = self.datePicker.date.description; // set text to date description
}
-(void)viewDoubleTapped:(UITapGestureRecognizer *)tapGR{
[_inputField resignFirstResponder]; // upon double-tap dismiss picker
}
-(void)textFieldBeganEditing:(NSNotification *)note{
_inputField = note.object; // set ivar to current first responder
}
-(void)textFieldEndedEditing:(NSNotification *)note{
_inputField = nil; // the first responder ended editing CRITICAL:avoids retain cycle
}
// INITI METHODS
-(void)initializationCodeMethod{
_datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, 320, 0)];// All pickers have preset height
self.bounds = _datePicker.frame; // Make our view same size as picker
[self addSubview:_datePicker];
[_datePicker addTarget:self action:@selector(pickerValueChanged:) forControlEvents:UIControlEventValueChanged]; // register to be notified when the value changes
// As an example we'll use a tap gesture recognizer to dismiss on a double-tap
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewDoubleTapped:)];
tapGR.numberOfTapsRequired = 2; // Limit to double-taps
[self addGestureRecognizer:tapGR];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(textFieldBeganEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil]; // Ask to be informed when any textfield begins editing
[center addObserver:self selector:@selector(textFieldEndedEditing:) name:UITextFieldTextDidEndEditingNotification object:nil]; // Ask to be informed when any textfield ends editing
}
-(id)init{
if ((self = [super init])){
[self initializationCodeMethod];
}
return self;
}
-(id)initWithFrame:(CGRect)frame{
if ((self = [super initWithFrame:frame])){
[self initializationCodeMethod];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])){
[self initializationCodeMethod];
}
return self;
}
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidBeginEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidEndEditingNotification object:nil];
}
@end
Then in view did load you would use this class like this:
ExampleBasicDateInputView *dateEntryView = [[ExampleBasicDateInputView alloc] init];
self.dueDate.inputView = datePickerView;
And as you see in the .h
file we've exposed the date picker instance as a property so you can set the style. etc. like so:
dateEntryView.datePicker.datePickerMode = UIDatePickerModeDate;
Obviously this is a very basic example, but I think it shows what can be done.
add UITextField's delegate in .h file to call this function when touched. then use the text field's tag value to determine what you want to do when the field is selected.
-(BOOL) textFieldShouldBeginEditing:(UITextField *) textField
{
activeTextField = textField;
if (textField.tag == 1)
{
self.datePicker.datePickerMode = UIDatePickerModeDate;
self.isDatePicker = TRUE;
self.tempTextField = textField;
[self showPicker];
return NO;
}
else if (textField.tag == 2)
{
self.datePicker.datePickerMode = UIDatePickerModeTime;
self.isDatePicker = TRUE;
self.tempTextField = textField;
[self showPicker];
return NO;
}
else if (textField.tag == 3)
{
self.isDatePicker = FALSE;
self.tempTextField = textField;
[self showPicker];
return NO;
}
else
{
self.tempTextField = textField;
return YES;
}
}
It is very easy. Defines delegate TextField (UITextFieldDelegate) in the .h in the viewDidLoad .m
myTextField.setDelegate = self;
In the same viewDidLoad associates the datePicker to myTextField.
myTextField.inputView = myDatePicker;
You can also do anime, but this is the easiest way.