Chris Rutkowski
Chris Rutkowski

Reputation: 1834

UITableViewController with picker view

I've a serious problem, and I cannot solve it by myself. I've spent hours searching the documentations, programming guides as well as developer forums and stack overflow.

The problem is I want to display a picker view in UITableViewController. I have a screen that has multiple text fields allowing me to search by title/author/keywords... and I'd also like to specify the minimum and maximum dates, using the UIDatePicker (or UIPickerView - to specify "last 5 days" for example).

I want to use UITableViewController because it saves me a lot of time resizing the table while the keyboard pops up when user presses the text field. In fact I've never been able to reproduce this animation using UIViewController and listening to textfields' delegate. It was almost perfect but there were some visible disadvantages comparing to the behaviour of table if displayed using UITableViewController.

So everything's fine when there are only textfields. But what about the date fileds? I want to make it exactly like the Contacts.app by Apple when I want to add a new contact and specify the birthday. In that application the Date Picker is shown, the table is resized, switching between email/phone field and birthday works great. I could believe that the date picker is in this case the keyboard but not for typing phone/email but date because it slides in/out just like a keyboard and is replaced instantly when the keyboard/picker is opened.

How did thet accomplished it? Or where can I find the easiest solution to reproduce it. I believe it cannot be as hard because it's very common situation.

Regards Chris

Upvotes: 4

Views: 5368

Answers (4)

Chris Rutkowski
Chris Rutkowski

Reputation: 1834

All of that is pointless. We should deal with the inputView and inputAccessoryView, where inputView should has the picker and inputAccessoryView the toolbar.

Upvotes: 7

DTs
DTs

Reputation: 1316

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *targetCell = [tableView cellForRowAtIndexPath:indexPath];
    self.pickerView.date = [self.dateFormatter dateFromString:targetCell.detailTextLabel.text];

    // check if our date picker is already on screen
    if (self.pickerView.superview == nil)
    {
        [self.view.window addSubview: self.pickerView];

        // size up the picker view to our screen and compute the start/end frame origin for our slide up animation
        //
        // compute the start frame
        CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
        CGSize pickerSize = [self.pickerView sizeThatFits:CGSizeZero];
        CGRect startRect = CGRectMake(0.0,
                                      screenRect.origin.y + screenRect.size.height,
                                      pickerSize.width, pickerSize.height);
        self.pickerView.frame = startRect;

        // compute the end frame
        CGRect pickerRect = CGRectMake(0.0,
                                       screenRect.origin.y + screenRect.size.height - pickerSize.height,
                                       pickerSize.width,
                                       pickerSize.height);
        // start the slide up animation
        [UIView beginAnimations:nil context:NULL];
            [UIView setAnimationDuration:0.3];

            // we need to perform some post operations after the animation is complete
            [UIView setAnimationDelegate:self];

            self.pickerView.frame = pickerRect;

            // shrink the table vertical size to make room for the date picker
            CGRect newFrame = self.tableView.frame;
            newFrame.size.height -= self.pickerView.frame.size.height;
            self.tableView.frame = newFrame;
        [UIView commitAnimations];

        // add the "Done" button to the nav bar
        self.navigationItem.rightBarButtonItem = self.doneButton;
    }
}

- (void)slideDownDidStop
{
    // the date picker has finished sliding downwards, so remove it
    [self.pickerView removeFromSuperview];
}

- (IBAction)dateAction:(id)sender
{
    NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
    cell.detailTextLabel.text = [self.dateFormatter stringFromDate:self.pickerView.date];
}

- (IBAction)doneAction:(id)sender
{
    CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
    CGRect endFrame = self.pickerView.frame;
    endFrame.origin.y = screenRect.origin.y + screenRect.size.height;

    // start the slide down animation
    [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.3];

        // we need to perform some post operations after the animation is complete
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(slideDownDidStop)];

        self.pickerView.frame = endFrame;
    [UIView commitAnimations];

    // grow the table back again in vertical size to make room for the date picker
    CGRect newFrame = self.tableView.frame;
    newFrame.size.height += self.pickerView.frame.size.height;
    self.tableView.frame = newFrame;

    // remove the "Done" button in the nav bar
    self.navigationItem.rightBarButtonItem = nil;

    // deselect the current table row
    NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}

You can download a full working sample app from Apple demonstrating just this. http://developer.apple.com/library/ios/#samplecode/DateCell/Introduction/Intro.html

Upvotes: 0

Daddy
Daddy

Reputation: 9035

You're going to have to create a UIWindow object, then add a view. The windowLevel property makes it higher than the statusBar, which you may or may not want.

//statusWindow is a UIWindow ivar declared in the header
//pickerShowing is declared as a BOOL in header
//release and removeFromSuperview is done in the animation delegate methods

//ANIMATE IN

-(void)slideIn {
    CGRect pickerFrame = CGRectMake(0.0f, 0.0f, 320.0f, 200.0f); //guessing on height
    UIView *viewForPicker = [[UIView alloc] init];
    UIPickerView *aPicker = [[UIPickerView alloc] init]; //don't forget to set delegate and dataSource
    viewForPicker.frame = pickerFrame;
    statusWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0.0, 480.0, 320.0f, 200.0f)];//guessing on height, y value is off the screen (bottom)
    statusWindow.windowLevel = UIWindowLevelStatusBar;
    statusWindow.hidden = NO;
    statusWindow.backgroundColor = [UIColor clearColor];
    [statusWindow makeKeyAndVisible];
    [viewForPicker addSubview:aPicker];
    [statusWindow addSubview:viewForPicker];
    [viewForPicker release];
    [aPicker release];
    [UIView beginAnimations:@"slideUp" context:nil];
    [UIView setAnimationDuration:0.3];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationFinished:)];
    statusWindow.frame = CGRectMake(0.0f, 200.0f, 320.0f, 200.0f); //guessing on y and height values, change them to suit needs 
    [UIView commitAnimations];
    pickerShowing = YES;
}


//ANIMATE out:



-(void)slideOut {
    [UIView beginAnimations:@"slideDown" context:nil];
    [UIView setAnimationDuration:0.3];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationFinished:)];
    statusWindow.frame = CGRectMake(0.0f, 480.0f, 320.0f, 200.0f);
    [UIView commitAnimations];
    pickerShowing = NO;
}

-(void)animationFinished:(NSString *)name {
    if ([name isEqualToString:@"slideDown"]) {
        [statusWindow release];
    }
}

Upvotes: 1

jv42
jv42

Reputation: 8593

If you want to slide in/out the picker view, you can use Core Animation. Simplest snippet:

// Slide picker view in
[UIView beginAnimations: @"SlideIn" context: nil];
myPickerView.frame = upFrame;
[UIView commitAnimations];

// ...

// Slide picker view out
[UIView beginAnimations: @"SlideOut" context: nil];
myPickerView.frame = downFrame;
[UIView commitAnimations];

upFrame and downFrame are CGRect you make with the right position for your picker view on screen and off screen respectively.

Hope this helps.

Upvotes: 0

Related Questions