iOS UIDatePicker Example with Done Button in Navigation Bar

UIDatePicker View looks like a casino slot machine with rolling wheels thats helps the user choose date and time. You can always check for the current date sent in the date picker or use the event named UIControlEventValueChanged to receive notification to changes in the date picker.

We review both these scenarios in this example where we create and display a Date Picker when the user selects a cell in the Table View and then selects a date or time or both date and time depending date picker mode. We log the changes to the picker values with the help of the action method associated with the UIControlEventValueChanged event. In addition to that when we display the date picker we also add a button to the Navigation which the user can tap to close the date picker and set the value of the selected cell based on the picker value.

iOS UIDatePicker Example with Table View
iOS UIDatePicker Example with Done Button
iiOS UIDatePicker Example with Time Selection
Create a new Project to create an iOS application with template as Empty Application. In the Product Name and Class prefix enter "DatePicker". Check the box "Use Automatic Reference Counting" (ARC) and then choose where you want to create your project.
iOS UIDatePicker Project with Done button in Navigation Bar

Interface file for the application delegate - DatePickerAppDelegate.h

#import <UIKit/UIKit.h>
#import "MyViewController.h"

@interface DatePickerAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UINavigationController    *navigationController;
@property (strong, nonatomic) MyViewController       *myViewController;

@end

Implementation file for the application delegate - DatePickerAppDelegate.h

#import "DatePickerAppDelegate.h"


@implementation DatePickerAppDelegate

@synthesize navigationController, myViewController;


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    
    //create the navigation controller and add to the view
    navigationController = [[UINavigationController alloc] init];
    [self.window addSubview:[self.navigationController view]];
    
    //check if the my viewcontroller eixsts, otherwise create it
    if(self.myViewController == nil)
    {
        MyViewController *myTableView = [[MyViewController alloc] init];
        self.myViewController = myTableView;
    }
    
    //push the viewcontroller into the navigation viewcontroller stack
    [self.navigationController pushViewController:self.myViewController animated:YES];
    
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application{
    //do nothing
}

- (void)applicationDidEnterBackground:(UIApplication *)application{
    //do nothing
}

- (void)applicationWillEnterForeground:(UIApplication *)application{
    //do nothing
}

- (void)applicationDidBecomeActive:(UIApplication *)application{
    //do nothing
}

- (void)applicationWillTerminate:(UIApplication *)application{
   //do nothing
}

@end

Interface file for view controller - MyViewController.h

#import <UIKit/UIKit.h>

@interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong) UITableView *myTableView;

@property (nonatomic, strong) NSArray *dataArray;
@property (nonatomic, strong) NSDateFormatter *dateFormatter1;
@property (nonatomic, strong) NSDateFormatter *dateFormatter2;
@property (nonatomic, strong) NSDateFormatter *dateFormatter3;

@property (nonatomic, strong) UIDatePicker *myDatePicker;
@property (nonatomic, strong) UIBarButtonItem *doneButton;
@end

Implementation file for view controller - MyViewController.m

#import "MyViewController.h"

@interface MyViewController ()

@end

@implementation MyViewController

@synthesize myTableView;
@synthesize dataArray, dateFormatter1, dateFormatter2, dateFormatter3;
@synthesize myDatePicker, doneButton;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //create an array to help load Table View cells
    self.dataArray = [NSArray arrayWithObjects:
                      @"Selected Date",
                      @"Selected Time",
                      @"Selected Date and Time",
                      nil];
 
    //date formatter with just date and no time
 self.dateFormatter1 = [[NSDateFormatter alloc] init];
 [self.dateFormatter1 setDateStyle:NSDateFormatterFullStyle];
 [self.dateFormatter1 setTimeStyle:NSDateFormatterNoStyle];
    
    //date formatter with no date and just time
    self.dateFormatter2 = [[NSDateFormatter alloc] init];
 [self.dateFormatter2 setDateStyle:NSDateFormatterNoStyle];
 [self.dateFormatter2 setTimeStyle:NSDateFormatterLongStyle];
    
    //date formatter with both date and time
    self.dateFormatter3 = [[NSDateFormatter alloc] init];
 [self.dateFormatter3 setDateStyle:NSDateFormatterFullStyle];
 [self.dateFormatter3 setTimeStyle:NSDateFormatterLongStyle];
    
    //find the available space on the screen
    CGRect tableViewFrame = self.view.bounds;
 
    //set the background color and create the table view
    self.view.backgroundColor = [UIColor whiteColor];
    self.myTableView = [[UITableView alloc] initWithFrame:tableViewFrame
                                                    style:UITableViewStyleGrouped];
    
    //set the delegate for the table view to self
    self.myTableView.delegate = self;
    
    //set the data source for the table view to self
    self.myTableView.dataSource = self;
    
    self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    
    //add the table view to the current view
    [self.view addSubview:self.myTableView];
    
}


//set the number of rows to the number of entries in the array
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    NSInteger result = 0;
    result = [self.dataArray count];
    return result;
}


//this to initialize the table view cell with data from the array
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    UITableViewCell *cell = nil;
    
    //check if this our table view
    if ([tableView isEqual:self.myTableView]){
        
        static NSString *TableViewCellIdentifier = @"MyCells";
        cell = [tableView dequeueReusableCellWithIdentifier:TableViewCellIdentifier];
        if (cell == nil){
            cell = [[UITableViewCell alloc]
                    initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:TableViewCellIdentifier];
        }
        
        //set the text for the cell with the data from the array
        cell.textLabel.text = [self.dataArray objectAtIndex:indexPath.row];
        
        //depending on the row set the date to current date with the proper format
        switch (indexPath.row) {
            case 0:
                cell.detailTextLabel.text = [self.dateFormatter1 stringFromDate:[NSDate date]];
                break;
            case 1:
                cell.detailTextLabel.text = [self.dateFormatter2 stringFromDate:[NSDate date]];
                break;
            case 2:
                cell.detailTextLabel.text = [self.dateFormatter3 stringFromDate:[NSDate date]];
                break;
            default:
                break;
        }
    }
    
    return cell;
    
}

//listen to changes in the date picker and just log them
- (void) datePickerDateChanged:(UIDatePicker *)paramDatePicker{
    if ([paramDatePicker isEqual:self.myDatePicker]){
        NSLog(@"Selected date = %@", paramDatePicker.date);
    }
}

//when the cell is selected in the table view we need to display the picker
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    
    //which section and row  was clicked on
    NSLog(@"Clicked on Section %d and Row %d", indexPath.section, indexPath.row);
    
    //get reference to the cell based on the index
    UITableViewCell *targetCell = [tableView cellForRowAtIndexPath:indexPath];
    
    //if date picker doesn't exists then create it
    if(self.myDatePicker == nil){
        self.myDatePicker = [[UIDatePicker alloc] init];
        
        //set the action method that will listen for changes to picker value
        [self.myDatePicker addTarget:self
                        action:@selector(datePickerDateChanged:)
                        forControlEvents:UIControlEventValueChanged];
    }
    
    
    //set the value of the picker based on the cell value and also set the proper picker mode
    switch (indexPath.row) {
        case 0:
            self.myDatePicker.date = [self.dateFormatter1 dateFromString:targetCell.detailTextLabel.text];
            self.myDatePicker.datePickerMode = UIDatePickerModeDate;
            break;
        case 1:
            self.myDatePicker.date = [self.dateFormatter2 dateFromString:targetCell.detailTextLabel.text];
            self.myDatePicker.datePickerMode = UIDatePickerModeTime;
            break;
        case 2:
            self.myDatePicker.date = [self.dateFormatter3 dateFromString:targetCell.detailTextLabel.text];
            self.myDatePicker.datePickerMode = UIDatePickerModeDateAndTime;
            break;
        default:
            break;
    }
    
    //find the current table view size
    CGRect screenRect = [self.view frame];
    NSLog(@"Screen frame %f %f", screenRect.origin.y, screenRect.size.height);
    
    //find the date picker size
    CGSize pickerSize = [self.myDatePicker sizeThatFits:CGSizeZero];
    
    //set the picker frame
    CGRect pickerRect = CGRectMake(0.0,
                                   screenRect.origin.y + screenRect.size.height - pickerSize.height,
                                   pickerSize.width,
                                   pickerSize.height);
    self.myDatePicker.frame = pickerRect;
    
    //add the picker to the view
    [self.view addSubview:self.myDatePicker];
    
    //create the navigation button if it doesn't exists
    if(self.doneButton == nil){
        self.doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done"
                                                           style:UIBarButtonItemStylePlain
                                                          target:self
                                                          action:@selector(dateSelected:)];
    }
    //add the "Done" button to the right side of the navigation bar
    self.navigationItem.rightBarButtonItem = self.doneButton;
    
    
}

//method to call when the "Done" button is clicked
- (void) dateSelected:(id)sender {
    
    //remove the "Done" button in the navigation bar
 self.navigationItem.rightBarButtonItem = nil;
 
 //find the current selected cell row in the table view
 NSIndexPath *indexPath = [self.myTableView indexPathForSelectedRow];
    UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
    NSLog(@"Selected Section %d and Row %d", indexPath.section, indexPath.row);
    
    //set the cell value from the date picker value and format it properly
    switch (indexPath.row) {
        case 0:
            cell.detailTextLabel.text = [self.dateFormatter1 stringFromDate:myDatePicker.date];
            break;
        case 1:
            cell.detailTextLabel.text = [self.dateFormatter2 stringFromDate:myDatePicker.date];
            break;
        case 2:
            cell.detailTextLabel.text = [self.dateFormatter3 stringFromDate:myDatePicker.date];
            break;
        default:
            break;
    }
    
    //remove the date picker view form the super view
    [self.myDatePicker removeFromSuperview];
    
    //deselect the current table row
    [self.myTableView deselectRowAtIndexPath:indexPath animated:YES];
    
}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Reference