How to popup a UIPickerView from the bottom of a UIScrollView in response to UITextField selection

It says to do this with

presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated

For the life of me, that wouldn’t work.  I could get it to popup sometimes, but with a horrible messed up UIPicker.  I added the UIPickerView to another UIView, which was put into a UIViewController, and handed that to the above method.

This worked brilliantly, BUT after animating from the bottom the background would go completely white.  Not good.

Welcome UIActionSheet

It is not available via the Interface Builder, which is where I endeavor to do all my UI (against the recommendations of everyone in the office.)

Basically, you create a UIActionSheet, add your UIPickerView to it, set the callback delegate (to get which button is clicked) and your away!

Code…

(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return (NSString*)[currentData objectAtIndex:row+1];
}
(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}

(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return [currentData count] 1;
}

Put that into your controller (and smoke it.)

(void) showPicker:(id)sender {
UIActionSheet *menu = [[UIActionSheet alloc] initWithTitle:[currentData objectAtIndex:0]
delegate:self
cancelButtonTitle:@"Done"
destructiveButtonTitle:@"Cancel"
otherButtonTitles:nil];

// Add the picker
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0,185,0,0)];

pickerView.delegate = self;
pickerView.showsSelectionIndicator = YES;    // note this is default to NO

[menu addSubview:pickerView];
[menu showInView:self.view];
[menu setBounds:CGRectMake(0,0,320, 700)];

[pickerView release];
[menu release];
}

It’s not pretty, but it works.  Again put that into your controller.

Respond to UIActionSheet buttons..

(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex==1){
if(currentField == location){
if(!completedOnce){
[website becomeFirstResponder];
}
}else{
completedOnce = YES;
}
}
}

Again, in your controller.  (I left in my actual code, to give an idea..)

What mine basically does is as follows

There are some minor details I have left out, but you should be able to fill in the gaps.

[Edit]
If you are wondering why I return the currentData objectAtIndex:row+1 it is because my arrays have the first Item the title of the UIPickerView.

regionData = [[NSArray arrayWithObjects:
@"Select Your Region",
@"Waikato",
@"Hawkes Bay",
@"Marlborough",
@"Taranaki",
@"Gisborne",
@"Bay of Plenty",
@"Nelson",
@"Otago",
@"Southland",
@"Northland",
@"Manawatu-Wanganui",
@"West Coast",
@"Canterbury",
@"Wellington",
@"Auckland",
@"Tasman", nil] retain];

Don’t forget to add

@interface myViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource, UIActionSheetDelegate> {

to your .h file.

[EDIT]
To get the selectedIndex from the UIPicker, you need to add the following to your controller. This is in response to a comment below.  I haven’t been deving the iPhone recently so I only guessed the below solution is correct (cherry picked it out of my code).  If not please point it out and I’ll go back and work it out again.

(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
selectedScrollIndex = row;
}

Posted on February 25, 2009 at 4:37 pm by Jordan Carter · Permalink
In: Iphone · Tagged with: , , ,

12 Responses

  1. Written by Noob
    on March 29, 2009 at 11:19 pm
    Permalink

    Great solution! But how did you manage to retrieve the selected value from the embedded picker?

  2. Written by Alex
    on March 30, 2009 at 6:14 am
    Permalink

    Hi mate,
    you helped me a lot. I have aproblem though. My pickerview is not populated. I have my arrays (2 columns) but it seems the data does not get in the picker. This is the code I have to populate it
    -(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    NSString *title = nil;

    switch(component)
    {
    case 0:
    if(row < [columnOneArray count])
    {
    title = [columnOneArray objectAtIndex:row];
    }
    break;
    case 1:
    if(row < [columnTwoArray count])
    {
    title = [columnTwoArray objectAtIndex:row];
    }
    break;
    }
    return title;
    }

  3. Written by Alex
    on March 30, 2009 at 7:14 am
    Permalink

    …one of my pickerView methods was mispelled.

  4. Written by Jordan
    on March 30, 2009 at 10:32 am
    Permalink

    I believe you use
    – (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    selectedScrollIndex = row;
    }

  5. Written by Jordan
    on March 30, 2009 at 10:38 am
    Permalink

    @Alex, mis-spelt method names are my biggest weakness. Also variables. Hurts me.

    Make use of declaring interfaces for your classes and it will give warnings that you are missing methods, provided it is a required method and not an optional one.

  6. Written by Chuck
    on April 10, 2009 at 10:46 am
    Permalink

    OK. I’m a noob. How do I call showPicker? I’m wanting it to happen when I go to edit a text field.

  7. Written by Jordan
    on April 14, 2009 at 12:45 pm
    Permalink

    Chuck :

    OK. I’m a noob. How do I call showPicker? I’m wanting it to happen when I go to edit a text field.

    When a UITextField gets textFieldShouldBeginEditing I return NO and instead call showPicker.

    Thats the kicker, you need to write in ‘textFieldShouldBeginEditing’ and then call showPicker, then return No.

    So the controller gets the textfield callback (via the being the delegate for the UITextField). It asks the controller should I show a keyboard, you say NO, and instead call the showpicker method.

  8. Written by Steven Veltema
    on January 19, 2010 at 2:28 pm
    Permalink

    I know this is old, but as a side note this can introduce a bug if the ActionSheet is dismissed while the picker is still animating the selection. The user will think that they have finished the selection but didSelectRow will not have been called before the ActionSheet dismissal. This can create problems if the UIPickerViewDelegate didSelectRow and the UIActionSheetDelegate willDismissWithButtonIndex both operate on the same property. I got hit with this and it took me a while to figure out what was going on.

  9. Written by bob
    on May 24, 2010 at 7:55 pm
    Permalink

    If anyone wants a fully functional reusable PickerControl that pops up and goes away with a combo box widget for your UITextFields that you can configure easily in IB email me at servertoodATgmail.com.

    You dont have to write any code just implement a protocol to get the data by a key.

  10. Written by jixx
    on August 17, 2010 at 8:24 am
    Permalink

    to use this solution in iPad as well, just correct the Rect of the Picker:

    // Add the picker
    UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0,185,0,0)];

    to

    // Add the picker
    UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0,185,320,216)];

    best regards & thanks

  11. Written by Ali
    on February 11, 2011 at 1:23 am
    Permalink

    do u have a complete sample code

  12. Written by Echilon
    on May 16, 2011 at 1:43 am
    Permalink

    Thanks for the info. A code sample would go a long way here.

Leave a Reply