How to create a custom UIPickerView

Creating picker views is similar to creating table views: you supply an array of data for each component by conforming to the UIPickerViewDataSource protocol.

A component is equivalent to a section in a table view, and each component can have several sections. You can’t set much of this up in interface builder other than add the actual picker view to a position, and define the delegate and data source for your class (self in our example).

Setting up the picker

Let’s go through this step by step. We’re creating a single component picker and print its results. First we need an array of data – let’s create this as a custom initialiser for a property named pickerData:

- (NSArray *)pickerData {
    
    if (!_pickerData) {
        _pickerData = @[@"Tom", @"Dick", @"Harry", @"Steve", @"Jones", @"Fred", @"Ninja", @"Mom"];
    }
    return _pickerData;
}

Next we’ll conform to the data source protocol with these snazzy methods:

#pragma mark - The Picker Challenge

-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    
    return [self.pickerData count];
}

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

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    
    UILabel *thisLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 40)];
    thisLabel.text = [self.pickerData objectAtIndex:row];
    
    return thisLabel;
}

We specify the amount of data in each section (how many components, how many rows), and return an object to be displayed in each row – like we would specify the cell for a table view.

Return types for the UIView can be either a UILabel or a UIImage – which allows you to be rather creative. Alternatively, if you’re simply presenting NSString data, use this method instead:

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

You can specify how tall each picker row needs to be by adding this method and play with the value:

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component {
    
    return 80;
}

Likewise you can specify how wide a component should be by implementing pickerView:widthForComponent. This should display your UIPickerView.

Reacting to changes

Unlike the UIDatePickerView, the standard UIPicker does not have an IBAction you can hook up. Instead, we can confirm to the UIPickerViewDelegate protocol and implement didSelectRow:inComponent – much like we would implement didSelectRowAtIndexPath for a table view:

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    
    int chosen = [pickerView selectedRowInComponent:component];
    NSLog(@"You've chosen %@", [self.pickerData objectAtIndex:chosen]);
}

That’s all there’s to it!

Perhaps one more thing: when the picker shows the first item in the list will be pre-selected. If you’d like to pre-select a different item you can do so by calling this, perhaps in your viewDidLoad method:

[self.yourPicker selectRow:14 inComponent:0 animated:NO];




Jay is the CEO and founder of WP Hosting, a boutique style managed WordPress hosting and support service. He has been working with Plesk since version 9 and is a qualified Parallels Automation Professional. In his spare time he likes to develop iOS apps and WordPress plugins, or draw on tablet devices. He blogs about his coding journey at http://wpguru.co.uk and http://pinkstone.co.uk.