Custom UITableCell and UIDatePicker - ios

I have created a custom UITableViewCell and assigned it to a custom class.
The custom cell has two labels and one uitextfield in it. Everything works great, but I need to be able to edit the text field with a date picker. I can't seem to figure out how to make the textfield's inputview the date picker? I can do it fine in a regular cell, but can't find a way to access it in my custom cell?
NSDate *eventDt= [gregorian dateByAddingComponents:offsetComponents toDate:[self trialDate] options:0];
// NSLog(#"EVENT DATE: %#", eventDt);
NSDateFormatter* dateF = [[NSDateFormatter alloc] init];
[dateF setDateFormat:#"MMMM dd, yyyy"];
[dateF setTimeZone:[NSTimeZone localTimeZone]];
NSString *eventDtforDisplay = [dateF stringFromDate:eventDt];
resultscell.labelEventDesc.numberOfLines=0;
[resultscell.labelEventDesc sizeToFit];
[resultscell.labelEventDate setText:[NSString stringWithFormat:#"%#",eventDtforDisplay]];
this is my problem----> [resultscell.textEventDate.inputView = [self datePicker];
[resultscell.textEventDate setText:[NSString stringWithFormat:#"%#",eventDtforDisplay]];
return resultscell;
}

In custom cell you can do this very well in the constructor (init method) of the cell as parameter, or create a setter method. so you don't have to touch the UITextField in the parent class, but only handle the inputView in the cells setter method.
Seems also like handling with delegates and protocols could be usefull here. If you don't know how, here a small example: Creating uitableview forms with uitextfields

Related

Custom cell UITextField updated in all cells across all sections

This is a dynamic prototype UITableView: In my cellForRowAtIndexPath:
I have dequequed my custom cell and this works just fine:
TimeSetViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:#"timeCell" forIndexPath:indexPath];
Next I set TimePicker to UITextField in timeCell and this works fine as well (i.e. the time picker displayed onclick of UITextField in timeCell) :
// Start Time
UIDatePicker *sTimePicker = [[UIDatePicker alloc]init];
sTimePicker.datePickerMode = UIDatePickerModeTime;
sTimePicker.backgroundColor = [UIColor whiteColor]
[cell.startTripTime setInputView:sTimePicker];
// End Time
UIDatePicker *eTimePicker = [[UIDatePicker alloc]init];
eTimePicker.datePickerMode = UIDatePickerModeTime;
eTimePicker.backgroundColor = [UIColor whiteColor];
[cell.endTripTime setInputView:eTimePicker];
Next I wanted to update the cell's UITextField through an event, in which I have understood from #Mani's post, I have set:
sTimePicker.tag = 1;
eTimePicker.tag = 2;
[sTimePicker addTarget:self action:#selector(updateTextField:)
forControlEvents:UIControlEventValueChanged];
[eTimePicker addTarget:self action:#selector(updateTextField:)
forControlEvents:UIControlEventValueChanged];
And in my custom method -(void)updateTextField:(UIDatePicker *)sender I have included this:
//Date Formatter
NSDateFormatter *dateFormat = [[NSDateFormatter alloc]init];
[dateFormat setTimeStyle: NSDateFormatterShortStyle];
if(sender.tag == 1){
//Get Start Date
UIDatePicker *starttimepicker = (UIDatePicker*)sender.inputView;
thisStartTime = [starttimepicker date];
//Display Date
NSString *startTimeText = [dateFormat stringFromDate:thisStartTime];
sTimeText = [NSString stringWithFormat:#"%#",startTimeText];
}
if(sender.tag == 2){
//Get End Date
UIDatePicker *endtimepicker = (UIDatePicker*)sender.inputView;
thisEndTime = [endtimepicker date];
//Display Date
NSString *endTimeText = [dateFormat stringFromDate:thisEndTime];
eTimeText = [NSString stringWithFormat:#"%#",endTimeText];
}
Question Update
I managed to pass startTimeText and endTimeText to cell.startTripTime.text and cell.endTripTime.text through sTimeText and eTimeText.
And I used [_tableView reloadData]; in -(void)updateTextField:(UIDatePicker *)sender (after the two if blocks) and the data is displayed in my cell.startTripTimeand cell.endTripTime UITextField, but it appears the same in across of my sections, while I want it to change only the first section's time, how can I fix that?
//I couldn't include the image but the output of the UITableView looks like this:
_________________________
Section 1
_________________________
Start Time : 4:50 PM
_________________________
End Time: 5:50 PM
_________________________
Section 2
_________________________
Start Time : 4:50 PM
_________________________
End Time: 5:50 PM
_________________________
And the [_tableView reloadData]; seems to interfere and reloads the view while I haven't even finish picking the time that I wanted, how can I fix this too?
The action method should be sent to one of the picker, the startStripTime seems to be a UIView instance not a UIDatePicker instance.
It is he date picker that changes its value, not the view containing it.
You should change also the update method accordingly.

UIPicker cannot be a delegate?

I created an IBOutlet for a UIPicker and named it 'RequestedDate.' I then went on the type
_RequestedDate.delegate = self;
but I keep getting the error:
property 'delegate' not found on object type 'UIDatePicker'
I am relatively new with Xcode and am just starting to work with code. Is there something I am doing wrong or cannot I not have a delegate for a UIPicker?
Thanks~
UIDatePicker uses the target-action pattern instead of the delegate pattern.
You either add a IBAction for the 'value changed' event in Interface Builder or you do it in code like this:
UIDatePicker *datePicker = [[UIDatePicker alloc] init];
[datePicker addTarget:self action:#selector(datePickerDidChange:) forControlEvents:UIControlEventValueChanged];
// ...
Then you implement the action method, and can retrieve the new date.
- (void)datePickerDidChange:(UIDatePicker *)picker {
NSDate *newDate = picker.date;
NSLog(#"Picker changed date to %#", newDate);
}
UIPickerView and UIDatePicker only look similar, they are completely separate classes. UIPickerView is a subclass of UIView and UIDatePicker is a subclass of UIControl, they are not related.
I don't think UIDatePicker has a delegate property. https://developer.apple.com/library/ios/documentation/uikit/reference/UIDatePicker_Class/Reference/UIDatePicker.html
What are you trying to do exactly?

Performing a specific action (like setting a UIDatePicker's date) based on being segued from a specific Table View

I have what appears to be a simple problem.
I have a table view controller (part of a 2 tabbed tab bar) which is populated by the user tapping the plus button in the navigation bar and filling in some information. That takes the user to an "Add Entry" view controller.
I have a second table view (second tab of the tab bar) which also has a plus button in the navigation bar which also calls the Add Entry. However, with this table view, I am already populating a textField and the datePicker to be related to the information it came from.
In the prepareForSegue, I'm setting the date and the text field. That works. However, I'm not entirely sure where to place the code in the Add Entry to say "If you're called from tab 1, leave everything blank and if you're called from tab 2, set the date picker".
In the prepareForSegue:
if ([segue.identifier isEqualToString:#"Create New Entry From Event"])
{
AddEntryViewController *addEntryViewController = (addEntryViewController *)segue.destinationViewController;
[addEntryViewController setSelectedEvent:self.occasion.title];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MMMM d, yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:sectionTitle];
[addEntryViewController setSelectedDate:dateFromString];
}
The setSelectedDate is:
- (void)setSelectedDate:(NSDate *)selectedDate
{
_selectedDate = selectedDate;
}
If I set the viewWillAppear to:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.occasionTextField.text = self.selectedEvent;
[self.datePicker setDate:self.selectedDate animated:YES];
}
I get a crash when calling the Add Entry from any other screen but this one which of course isn't desirable.
So I need a way to leave all text fields and the date picker as blank when called from anywhere in the app (which works without the self.datePicker line) and to only SET the datePicker when being called from THAT particular table view.
Any thoughts on this would be really great!
in interface define a BOOL like this.
#property (assign, nonatomic) BOOL fromTabOne;
and add
#synthesize fromTabOne;
in viewWillAppear
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!self.fromTabOne) {
self.occasionTextField.text = self.selectedEvent;
[self.datePicker setDate:self.selectedDate animated:YES];
}
}
in prepareForSegue
if ([segue.identifier isEqualToString:#"Create New Entry From Event"])
{
AddEntryViewController *addEntryViewController = (addEntryViewController *)segue.destinationViewController;
[addEntryViewController setSelectedEvent:self.occasion.title];
if (viewOne) { //if you're on first tab
[addEntryViewController setFromTabOne:YES];
} else {
[addEntryViewController setFromTabOne:NO];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MMMM d, yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:sectionTitle];
[addEntryViewController setSelectedDate:dateFromString];
}
}
The error you mentioned in comment probably caused by a nil NSDate or wrong locale settings. Make a nil check before setting. I guess the NSDateFormatter couldn't format your string.

IOS Date Picker Like A Popup Keyboard Functionality?

Considering a data entry form (scrollable view) that has 8 text field entries and 4 date field entries, Is it possible to present a date-picker at the bottom where normally (and how normally a keyboard would pop up), depending on which text field the user tapped into?
I suppose you can present a date picker modally with code, but it seems presenting a date-picker the same way a keyboard is called and presented would be a built in to the SDK or am I missing something? (set an attribute in the nib editor to tell the view that this text field accepts a date, and to give you a date picker option in addition to the variety of keyboards)
It blows my mind why developers don't have a simple way to "pop-up" a calendar or date picker when a declared date field gets the focus.
Any example apps or tutorials that you know of you can point me towards?
I just researched this same question, and while the web is replete with 3rd party libraries and tricky hacks, there's actually a pretty simple, and probably preferred way of accomplishing what you're after.
First of, it leverages the capabilities offered by the UITextField inputView and input accessoryView properties, which together offer endless customization possibilities. The problem for me became knowing how to structure things to get exactly what I wanted. I suggest reading about them here:
https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/InputViews/InputViews.html
As such, I started by declaring two properties:
#property (nonatomic, strong) UIDatePicker *datePicker;
#property (nonatomic, strong) UIView *datePickerToolbar;
and then created each of them with something like the following:
- (UIView*)datePickerToolbar {
if (!_datePickerToolbar) {
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
toolbar.barStyle = UIBarStyleBlack;
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStylePlain target:self action:#selector(datePickerCanceled:)];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(datePickerDone:)];
UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[toolbar setItems:[NSArray arrayWithObjects:cancelButton, space, doneButton, nil] animated:NO];
_datePickerToolbar = toolbar;
}
return _datePickerToolbar;
}
- (UIDatePicker*)datePicker {
if (!_datePicker) {
UIDatePicker *datePicker = [[UIDatePicker alloc] init];
datePicker.datePickerMode = UIDatePickerModeDate;
datePicker.date = [NSDate date];
_datePicker = datePicker;
}
return _datePicker;
}
And of course, you can customize these views to suit your needs. Since these views are your own, however, you'll also need to decide how each button in the toolbar should handle interaction. While both should dismiss the "keyboard" (which is done by resigning first responder), in my case I also wanted the Done button to set the date input field to a formatted string of the selected date:
- (void)datePickerCanceled:(id)sender {
// just resign focus and dismiss date picker
[self.dateOfBirthField resignFirstResponder];
}
- (void)datePickerDone:(id)sender {
NSDate *selectedDate = self.datePicker.date;
// format date into string
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
// format overall string
NSString *dateString = [dateFormatter stringFromDate:selectedDate];
self.dateInputField.text = dateString;
[self.dateOfBirthField resignFirstResponder];
}
After that, the only thing left to do to trigger our keyboard replacement is to assign our custom views to those properties UITextField properties I mentioned earlier, which I chose to do in 'ViewDidLoad`:
- (void)viewDidLoad {
[super viewDidLoad];
self.dateInputField.inputView = self.datePicker;
self.dateInputField.inputAccessoryView = self.datePickerToolbar;
}
I hope this is what you were looking for. After seeing everything out there, I'm convinced that this is the simplest, most manageable way to do it. I also like this approach because it can be modified and repurposed easy enough for different input requirements.
A hidden gem, in my opinion.

iOS strange keyboard-hiding behavior when adding a subview

I have a view with an UITextField and need to show an UIDatePicker (it's hidden below the keyboard) when a button is pressed.
I'm lazily instantiating the date picker because this allows me to show the view way more fast.
This is the code associated with the tap on the button:
- (IBAction)hideKeyboard {
if (!self.datePicker) {
// UIDatePicker allocation and initialization
self.datePicker = ...
...
[self.view addSubview:self.datePicker];
}
[self.textField resignFirstResponder];
}
What happens is that this interfere with the keyboard hiding animation. Actually there is no animation at all.
Another clue I have is that this doesn't happen on the simulator, but only on the actual device (an iPhone 4S).
How can I solve this?
EDIT:
Setting the datePicker as the inputView of the textField doesn't solve my problem.
I can recommend you another solution then hiding keyboard and using button for showing the date picker.
If I understood you correctly you want to show a date picker when user taps on the textfield and then maybe you set the date in textfield.
UITextField has a property
#property (readwrite, retain) UIView *inputView
If you set the inputView property to date picker then the textfield will show date picker instead a keyboard (and even animated like keyboard).
Of course the values need to get your own and set to textfield.
Edit reason: Question edited
I do not know why setting the datepicker as the input view did not help. Anyway if you do not want the keyboard shown and show the datepicker by adding a subview you can use the following delegate method of UITextField
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
implement the delegate method. In the method just add pickerview as subview to your view and return NO for not to show the keyboard.
Edit reason: Commend
Is there any reason why you do not use textfield? If not I would use it, because it makes everything easier. If you want to use for some reason the UILabel then you can watch the keyboard notification. When did the keyboard disapeared and then show the datepicker.
For keyboard notifications please refer here, good explained with sample codes, UIKeyboardDidHideNotification should help you
http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
Quite simple :
Just add a date picker object as the input value of your textfield. No need to show/hide the keyboard.
UIDatePicker *datePicker = [[UIDatePicker alloc] init];
NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar] ;
NSDate *currentDate = [NSDate date];
NSDateComponents *comps = [[NSDateComponents alloc] init] ;
[comps setYear:anyInteger];
NSDate *maximumDate = [calendar dateByAddingComponents:comps toDate:currentDate options:0];
[comps setYear:anyInteger;
NSDate *minimumDate = [calendar dateByAddingComponents:comps toDate:currentDate options:0];
[datePicker setMaximumDate:maximumDate];
[datePicker setMinimumDate:minimumDate];
datePicker.datePickerMode = UIDatePickerModeDate;
textField.inputView = datePicker;

Resources