Two UIPickerView together in one ViewController Programatically

| June 16, 2011 | 5 Comments

We will add two pickerviews programmatically.

Goal: we want to add two pickerviews in one viewcontroller. By pressing on a button will display a pickerview and when we will select from any of the pickerview its selected row will be displayed on button. When one button is pressed if other pickerview is on screen we will remove it. Also if user touches on any other part of the screen, both pickerviews will hide and removed.

Are your ready to Start?

Open the Xcode, From the file menu select New Project. Name the project PickerViewExample. Now add another view controller from Class->New->add File now select UIViewControllerSubClass. Check with Xib option and leave other as uncheck. HomeViewController is the class where we will create our two pickerviews.

Now open the HomeViewController.h and write following code

 #import 

@interface HomeViewController : UIViewController
< UIPickerViewDataSource,UIPickerViewDelegate> {
	UIPickerView *countryTypePicker;
	UIPickerView *categoryTypePicker;
	NSArray *countryTypes;
	NSArray *categoryTypes;
	IBOutlet UIButton *countryTypeBtn;
	IBOutlet UIButton *categoryTypeBtn;
      NSArray *pickersArray;
    UIPickerView *activePickerView;
}
@property (nonatomic,retain)     UIPickerView *activePickerView;
-(IBAction) showCountryTypePicker;
-(IBAction) showCategoryTypePicker;
@end

Open the HomeViewController Nib and add two buttons. One button will contain selected country and one will contain select category.Assign tag 0 and 1 to both these buttons. Also there are two function attached with buttons showCountryTypePicker and ShowCategoryTypePicker.

Now under first line of HomeViewController add following lines

#define kPICKERCOLUMN 1
#define kCATEGORYTYPEPICKERTAG 20
#define kCUISINETYPEPICKERTAG 21

first line shows number of columns in each picker while second and third line are unique tags that we will assign to each picker.

 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization.
		categoryTypes = [[NSArray alloc] initWithObjects:@"Appetizers",@"Breakfast",@"Dessert",@"Drinks",
						 @"Main Dish/Entree", @"Salad", @"Side Dish", @"Soup", @"Snack",
						 @"Baby Food", @"Pet Food",nil];  

		countryTypes = [[NSArray alloc] initWithObjects:@"African",@"American",@"Armenian",@"Barbecue",
						 @"Brazilian", @"British", @"Cajun", @"Central American", @"Chicken",
						 @"Chinese", @"Cuban",
						 @"Ethiopian", @"French", @"Greek", @"German", @"Hamburgers",
						 @"Homestyle Cooking", @"Indian", @"Irish", @"Italian", @"Jamaican",
						 @"Japanese", @"Korean", @"Mexican", @"Middle Eastern", @"Pakistani",
						 @"Pancakes /Waffles", @"Persian", @"Pizza", @"Polynesian", @"Russian",
						 @"Sandwiches", @"Seafood", @"Scandinavian", @"Spanish", @"Soul Food",
						 @"South American", @"Steak", @"Vegetarian", @"Tex-Mex", @"Thai",
						 @"Vietnamese",@"Wild Game",nil];
    }
    return self;
}

These are two arrays that we will bind with two pickers.
Now uncomment the viewDidLoad method and replace with following

- (void)viewDidLoad {
    [super viewDidLoad];
	categoryTypePicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0,250,400,160)];
	categoryTypePicker.tag = kCATEGORYTYPEPICKERTAG;
	categoryTypePicker.showsSelectionIndicator = TRUE;
	categoryTypePicker.dataSource = self;
	categoryTypePicker.delegate = self;
	categoryTypePicker.hidden = YES;
	countryTypePicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0,250,400,160)];
	countryTypePicker.backgroundColor = [UIColor blueColor];
	countryTypePicker.tag = kCUISINETYPEPICKERTAG;
	countryTypePicker.showsSelectionIndicator = TRUE;
	countryTypePicker.hidden = YES;
	countryTypePicker.dataSource = self;
	countryTypePicker.delegate = self;
pickersArray =  [[NSArray alloc] initWithObjects: categoryTypePicker, countryTypePicker ,nil];//add your both pickers to this array and we will use button tags to get picker from this array and alternate between two pickers
}

Initially both pickers will be hidden. We assigned different tag to each picker.
If we want to hide the pickerview if touched outside the button add your code to following method

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)eve
{

}
#pragma mark -
#pragma mark picker methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
	return kPICKERCOLUMN;
}

This method tells how many columns in each picker. We want one column in each picker.

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
	if (pickerView.tag == kCATEGORYTYPEPICKERTAG)
		return [categoryTypes count];
	else
		return [countryTypes count];

}

This method will tell how many rows in each picker based on tag it binds the relevant array.

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
	if (pickerView.tag == kCATEGORYTYPEPICKERTAG)
		return [categoryTypes objectAtIndex:row];
	else
		return [countryTypes objectAtIndex:row];

} //this mehtod shows title for each row in picker
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
	if (pickerView.tag == kCATEGORYTYPEPICKERTAG) {
		NSString *categoryType  = [categoryTypes objectAtIndex:[pickerView selectedRowInComponent:0]];
		[categoryTypeBtn setTitle:categoryType forState:UIControlStateNormal];	

	}else {

		NSString *countryType  = [countryTypes objectAtIndex:[pickerView selectedRowInComponent:0]];
		[countryTypeBtn setTitle:countryType forState:UIControlStateNormal];				

	}	

} //this method displays whenever selection indicator stops the row title is set as button title.
//Thanks to Nick Staresinic for pointing out this bug..
//call this function on both button clicks
-(IBAction) alternatePickers: (id) sender{	

        UIButton * control = (UIButton*) sender;
        if (self.activePickerView) {

            [self.activePickerView removeFromSuperview];

        }
        NSLog(@"Segment index:%d",control.tag);
        self.activePickerView = [pickersArray objectAtIndex:control.tag];

        [self.view  addSubview:self.activePickerView];

}

In above method if one of the button is pressed we hide other picker and remove it from view if it there. From Interface builder please connect this method with each button on Touchupinside event.
Now comes the memory management part. Replace your dealloc with follow method.

- (void)dealloc {
	[countryTypes release];
	[categoryTypes release];
	[categoryTypePicker release];
	[countryTypePicker release];;
    [super dealloc];
}

We have done most of our work now we will add our HomeViewController to main window. Open the PickerViewExampleAppDelegate.h above the implementation tag add @class HomeViewController. add following line
HomeViewController *homeViewController;
Now open PickerViewExampleAppDelegate.m and add HomeViewController.h. Now replace your following function with this

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    // Override point for customization after application launch.
    homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
	[window addSubview:homeViewController.view];
    [self.window makeKeyAndVisible];

    return YES;
}

In its dealloc you will release [homeViewController release];
Click here to download source code.
Developer: Asif Noor (asef.noor@gmail.com)

Tags: , , , , , ,

Category: IPhone

Comments (5)

Trackback URL | Comments RSS Feed

  1. Asif Noor says:

    Thanks Nick Staresinic for pointing out bug in alternating between two pickers.It is fixed now and also source code is update.

  2. pooja says:

    Thankyou so much for this example. It saved me a lot of time. I’ve to implement multiple pickers in my app but I have a problem. I need the contents of one picker to change based on another picker’s selection. For example – The regions picker should change according to the country selected in the country picker. Any help would be greatly appreciated as I’m a newbie to Objective C. Thanks a lot in advance.

  3. Asif Noor says:

    @Pooja,

    What you do is following.
    When country in the country picker changes, you should fire a notification and catch that notification in other picker and in that observer reload your region values.
    Hope it helps.

  4. David says:

    Great tute, but what if I dont want to fire from a button, but a press on a table view cell?

    Thanks

    • Asif Noor says:

      You can use table view delegate method

      - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      }

      When user presses any cell or row, this function will be called.

Leave a Reply