Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 7 - How to display a date picker in place in a table view?

With iOS7, Apple released the sample code DateCell.

enter image description here

Demonstrates formatted display of date objects in table cells and use of UIDatePicker to edit those values. As a delegate to this table, the sample uses the method "didSelectRowAtIndexPath" to open the UIDatePicker control.

For iOS 6.x and earlier, UIViewAnimation is used for sliding the UIDatePicker up on-screen and down off-screen. For iOS 7.x, the UIDatePicker is added in-line to the table view.

The action method of the UIDatePicker will directly set the NSDate property of the custom table cell. In addition, this sample shows how to use NSDateFormatter class to achieve the custom cell's date-formatted appearance.

enter image description here

You can download the sample code here: DateCell.


You can use the answer I had previously given below or use this new class in Swift I made to make this task a lot simpler and cleaner: https://github.com/AaronBratcher/TableViewHelper


I find the code provided by Apple to be problematic in a couple of ways:

  • You can't have a static tableView because they are using the tableView:cellForRowAtIndexPath method
  • The code crashes if you don't have additional rows below the last date picker cell

For static cell tables, I define my date picker cell below my date display cell and have a flag identifying if I'm editing it. If I am, I return a cell height appropriate, otherwise I return a cell height of zero.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 && indexPath.row == 2) { // this is my picker cell
        if (editingStartTime) {
            return 219;
        } else {
            return 0;
        }
    } else {
        return self.tableView.rowHeight;
    }
}

When the row showing the date is clicked, I change the flag and do the update animation to show the picker.

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 && indexPath.row == 1) { // this is my date cell above the picker cell
        editingStartTime = !editingStartTime;
        [UIView animateWithDuration:.4 animations:^{
            [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:2 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView reloadData];
        }];
    }
}

If I have multiple date/time pickers in the same table, I set the flags accordingly on the click and reload the appropriate rows. I've found that I can keep my static table, use a lot less code, and it is easier to understand what is happening.


Using the storyboard and a static table I was able to achieve the same result using the following code. This is a great solution because if you have many oddly shaped cells or want to have multiple cells that are dynamically shown/hidden this code will still work.

@interface StaticTableViewController: UITableViewController

@property (weak, nonatomic) IBOutlet UITableViewCell *dateTitleCell; // cell that will open the date picker. This is linked from the story board
@property (nonatomic, assign, getter = isDateOpen) BOOL dateOpen;

@end


@implementation StaticTableViewController

-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

    // This is the index path of the date picker cell in the static table
    if (indexPath.section == 1 && indexPath.row == 1 && !self.isDateOpen){
        return 0;
    }
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
    [tableView beginUpdates];
    if (cell == self.dateTitleCell){
        self.dateOpen = !self.isDateOpen;
    }
    [tableView reloadData];
    [self.tableView endUpdates];
}

I have taken the DateCell source from Apple, and removed the storyboard file.

If you want one without storyboard, take a look at: https://github.com/ajaygautam/DateCellWithoutStoryboard


One of the best tutorials about this is iOS 7 in-line UIDatePicker – Part 2. Basically here I use static table view cells and implement some additional methods. I used Xamarin and C# for this:

You have to active Clip Subviews.

Setting the height:

public override float GetHeightForRow (UITableView tableView, NSIndexPath indexPath)
{
    if (indexPath.Row == 4) {
        return (datePickerIsShowing) ? 206f : 0.0f;
    }

    return base.GetHeightForRow(tableView,indexPath);
}

Than a class variable: private bool datePickerIsShowing = false;

Show date picker:

private void showDatePickerCell(){
    datePickerIsShowing = true;
    this.TableView.BeginUpdates ();
    this.TableView.EndUpdates ();
    this.datePicker.Hidden = false;
    this.datePicker.Alpha = 0.0f;

    UIView.Animate (0.25, animation:
        () => {
            this.datePicker.Alpha = 1.0f;
        }
    );
} 

Hide date picker:

private void hideDatePickerCell(){
    datePickerIsShowing = false;
    this.TableView.BeginUpdates ();
    this.TableView.EndUpdates ();

    UIView.Animate (0.25,
        animation: () => {
            this.datePicker.Alpha = 0.0f;
        },
        completion: () => {
            this.datePicker.Hidden = true;
        }
    );
} 

And calling this functions:

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    if (indexPath.Row == 3) {
        if (datePickerIsShowing) {
            hideDatePickerCell ();
        } else {
            showDatePickerCell ();
        }
    }

    this.TableView.DeselectRow (indexPath, true);
}

I have made my own custom view controller to simplify the process of adding an inline picker inline in a tableview. You just subclass it and follow some simple rules and it handles the date picker presentation.

You can find it here along with an example project that demonstrates how to use it: https://github.com/ale84/ALEInlineDatePickerViewController