Expanding and collapsing UITableViewCells with DatePicker

I'm building an app that lets the user select dates from a UITableView. The tableView is static and grouped. I've looked through many questions, including this one, trying to figure out how to accomplish this - but nothing seems to work optimal. Apple's calendar app features a very smooth and nice animation that none of the examples I've been through have managed to recreate.

This is my desired result:

In-place date picker

Could someone point me to a tutorial or explain how I can accomplish such a smooth animation with the most concise and straight forward way of doing it, like we see in the calendar app?

Thanks alot!

Erik


Solution 1:

I assume you're using storyboard, the example is with UIPickerView: Create a tableviewcell right under the cell that contains the textfield you want to fill and set the cells row height to 216.0 in the inspector and add a UIPickerView to that cell.

see here

Next connect the UIPickerView via Outlet to your viewcontroller and add the following property to your ViewController.h:

@property (weak, nonatomic) IBOutlet UIPickerView *statusPicker;
@property BOOL statusPickerVisible;

In your ViewController.m do in viewWillAppear

self.statusPickerVisible = NO;
self.statusPicker.hidden = YES;
self.statusPicker.translatesAutoresizingMaskIntoConstraints = NO;

Add two methods:

- (void)showStatusPickerCell {
    self.statusPickerVisible = YES;
    [self.tableView beginUpdates];
    [self.tableView endUpdates];
    self.statusPicker.alpha = 0.0f;
    [UIView animateWithDuration:0.25 
                 animations:^{
                     self.statusPicker.alpha = 1.0f;
                 } completion:^(BOOL finished){
                     self.statusPicker.hidden = NO;
                 }];];
}

- (void)hideStatusPickerCell {    
    self.statusPickerVisible = NO;
    [self.tableView beginUpdates];
    [self.tableView endUpdates];
    [UIView animateWithDuration:0.25
                 animations:^{
                     self.statusPicker.alpha = 0.0f;
                 }
                 completion:^(BOOL finished){
                     self.statusPicker.hidden = YES;
                 }];
}

In heightForRowAtIndexPath

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat height = self.tableView.rowHeight;
    if (indexPath.row == 1){
        height = self.statusPickerVisible ? 216.0f : 0.0f;
    }
    return height;
}

In didSelectRowAtIndexPath

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        if (self.statusPickerVisible){
            [self hideStatusPickerCell];
        } else {
            [self showStatusPickerCell];
        }
    }
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}

Solution 2:

The 2 answers above enabled me to solve this problem. They deserve the credit, I'm adding this a reminder for myself - summary format.

This is my version of the above answers.

1. As noted above - add picker to a the cell you want to show / hide.

2. Add constraints for the picker in interface builder - center X / center Y / equal height / equal width to the cell's content view

3. Connect the picker to you VC

@IBOutlet weak var dobDatePicker: UIDatePicker!

You might as well control drag and add a method that will register the date changes

@IBAction func dateChanged(sender: UIDatePicker) { 
    // updates ur label in the cell above
    dobLabel.text = "\(dobDatePicker.date)"
}

4. In viewDidLoad

dobDatePicker.date = NSDate()
dobLabel.text = "\(dobDatePicker.date)" // my label in cell above
dobDatePicker.hidden = true

5. Setting cell heights, in my example the cell I want to expand is section 0, row 3... set this to what you cell you want to expand / hide. If you have many cells with various heights this allows for that.

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

    if indexPath.section == 0 && indexPath.row == 3 {
        let height:CGFloat = dobDatePicker.hidden ? 0.0 : 216.0
        return height
    }

    return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

6. Selecting the cell above to expand the one below, again set this to the cell you will tap to show the cell below.

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

let dobIndexPath = NSIndexPath(forRow: 2, inSection: 0)
if dobIndexPath == indexPath {

    dobDatePicker.hidden = !dobDatePicker.hidden

    UIView.animateWithDuration(0.3, animations: { () -> Void in
        self.tableView.beginUpdates()
        // apple bug fix - some TV lines hide after animation
        self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
        self.tableView.endUpdates()
    })
}
}

enter image description here