Blog
WORKING WITH PICKERS
Author: Paweł
Comments: 18 comments

Recently we had to create a registration form which allows you to set some different data like country, language, first and last name, date of birth, etc. It’s not a problem to edit text-like properties. All you need is to create a UITextField. Everything else is done automatically. When a text field gets a focus (or becomes a first responder – using iPhone‘s language) a keyboard panel appears at the bottom and you can change the field’s content.

But for some other fields – I’d like them to behave like combo boxes. Instead of typing the whole name of a country I prefer to select it from the list. Cocoa Touch framework doesn’t have a combo box – known from desktop apps – but it has something called UIPickerView. A UIPickerView is in fact a kind of combo box adopted to a multitouch device. So is UIDatePicker. The problem I faced using iPhone’s pickers was how to link them to the text fields. I found a hacky solution which consists in using a UIButton instead of UITextField and showing up a picker manually when the button is tapped. But there is much better and proper solution – inputView.

InputView is a property of UIResponder class – so also of UITextFiled class. When you set it to any custom view that view will appear any time your control becomes a first responder. Cool and smooth solution, isn’t it?

Below is a a piece of code of hooking up a UIPickerView to the UITextField.

UIPickerView *countryPicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
countryPicker.delegate = self;
countryPicker.dataSource = self;
[countryPicker setShowsSelectionIndicator:YES];
countryTextField.inputView = countryPicker;
[countryPicker release];

It’s all you need to show up a UIPickerView when you tap on a text field. Handling picker’s delegates is very easy.

For the UIPickerViewDataSource you just need to give a number of rows and columns of the picker view.

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    return countries.count;
}

UIPickerViewDelegate is used to:
- tell the control what values should be displyed at each row/column
- update the text field with already selected value

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return [countries objectAtIndex:row];
}

- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    countryTextField.text = (NSString *)[countries objectAtIndex:row];
}

Of course you can assign your custom view not only to UITextField objects but also to other UIControl-derived objects (UIControl inherits from UIView and UIView from UIResponder).
If you want to use the inputView property with buttons you have to create a new class that derives from UIButton, make inputView property writable and override canBecomeFirstResponder method (see the code below).

Header file

@interface CustomButton : UIButton
{
    UIView *_inputView;
}

@property (nonatomic, retain) UIView *inputView;

@end

Source file

#import "CustomButton.h"

@implementation CustomButton

@synthesize inputView = _inputView;

- (BOOL) canBecomeFirstResponder
{
    return YES;
}

@end

Tip:

If you wonder how to display a toolbar or any other view above your keyboard or picker (see picture above) then have a look at inputAccessoryView – another property of UIResponder class. It works exactly the same as the inputView.

The sample code for this article can be found here.

Paweł
Over 8 years of experience in the design and development of desktop applications, tools, graphics and user interfaces. Worked as a software developer for global companies such as Imagination Technologies and Codemasters.
  • Robbie

    Excellent and informative article, thanks for the info :)

  • http://rodliberal.com Rod

    Hi Pawel,

    Do you know if this can be used as a view that slides in and out from the bottom of the parent view like the keyboard?

    • Pawel

      Hi Rod,

      I double checked and it behaves exactly like the keyboard. When UITextField becomes first responder the intputView (keyboard or picker) slides up from the bottom. When the control resigns first responder the input view slides down. If you switch focus between multiple controls the InputView remains stationary (it doesn’t slide down and slide up with a new view) and I think it is default behaviour.

  • http://yasirmturk.com Yasir M Turk

    Excellent, but i want to ask that what if i need to display a Done button and a Cancel button along with the country picker just like keyboard in some cases.???? please help me

    • Pawel

      Are you talking about that blue button in the right bottom corner of the keyboard view? If you want to have such a button in the picker view you have to provide your own custom view.

  • http://www.stewartmacdonald.com.au Stewart Macdonald

    Thanks Pawel. Your code is just what I was after.

  • http://chrisjones.id.au Christopher Jones

    I have used your great technique in my code, but can’t find a way of hiding the flashing blue insertion point which appears when you edit a text field with a picker. It’s superfluous if the picker is going to replace the entire contents of the text field. Any ideas?

    • Paweł

      You can use custom UILabel instead of UITextField. Just override UILabel like I did it with UIButton:
      - override method canBecomeFirstResponder and return YES
      - in touchesEnded:withEvent: method call [self becomeFirstResponder]
      - make your UILabel userInteractionEnabled

  • Stine

    Hi :)

    I find this a very nice post as I am struggling to make a Sign Up page just like the one you describe.

    To avoid the blinking input cursor when editing a date entry I am trying to replace the text field with a label. One of my problems with this is that the label does not have an inputView and therefore I can no longer do the date picker trick?!

    What am I not getting right here? :D

    Thanks a lot,
    Stine

  • Stine Søndergaard

    Sorry, me again! Think I managed to make my label work by reading your post and your comment from today very thorough :) Thanks a lot!

  • http://chrisjones.id.au Christopher Jones

    Unfortunately, I can’t use your solution to avoid the flashing blue insertion point, as I need the Clear Button which you can put in a UITextField…

    • Paweł

      Chris, you can always extend your custom label by adding Clear Button.

  • Ben

    Great solution! However is there a way that when you tap on a text field then picker / keyboard slides up from the bottom of the screen, and then once you are finished with it it could slide back down?

    • Paweł

      When you are finished with your picker/keyboard just call [testField resignFirstResponder] and your picker/keyboard should slide back down.

  • rahul

    i want to use three different pickers for country,region and pin code.
    when i select country second picker change and show states of that country. after selecting state third picker changes.all three get data from a php website. plz help me…..

    first picker get data from website and when we select country it get data from website related to that country like this get pin no….

    • Paweł

      Hi Rahul, I don’t understand what your problem is. Why cannot you use three different pickers?

  • Johan

    This is exactly what I needed, Thanks!!

  • Ashfaque

    Nice explanation & easy to implement.. Thanks….