Wojtek @suda Siudzinski

ObjC/Python/Node developer, DIY hacker, rookie designer, 3D print junkie. CEO @ Issue Stand, Senior Full Stack @ Particle.io

Multiple Row Selection in UIPickerView

Recently, one of my projects needed user to select multiple values from a list that was about 150px high, which reminded me how Mobile Safari renders <select multiple="multiple">.
Problem is, UIPickerView doesn't allow multiple row selection (not publicly anyway), so I tried to use custom views and toggle their accessoryType.

Seems easy right? Nope. As it turns out, views inside UIPickerView don't receive any touch events. Some people even used UITableViews and dummy picker view to fake the effect.
Well, I found easier way. Since iOS 3.2, you can assign gesture recognizers to views. One of them is UITapGestureRecognizer, which can be assigned to view cells and toggle their selection :) It all comes to this two methods:

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    UITableViewCell *cell = (UITableViewCell *)view;
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
        [cell setBackgroundColor:[UIColor clearColor]];
        [cell setBounds:CGRectMake(0, 0, cell.frame.size.width - 20, 44)];
        cell.tab = row UITapGestureRecognizer * singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleSelection:)];
        singleTapGestureRecognizer.numberOfTapsRequired = 1;
        [cell addGestureRecognizer:singleTapGestureRecognizer];
    if ([selectedItems indexOfObject:[NSNumber numberWithInt:row]] != NSNotFound) {
        [cell setAccessoryType:UITableViewCellAccessoryCheckmark];
    } else { [cell setAccessoryType:UITableViewCellAccessoryNone];
    } cell.textLabel.text = [datasource objectAtIndex:row];
    return cell;

- (void)toggleSelection:(UITapGestureRecognizer *)recognizer {
    NSNumber *row = [NSNumber numberWithInt:recognizer.view.tag];
    NSUInteger index = [selectedItems indexOfObject:row];
    if (index != NSNotFound) {
        [selectedItems removeObjectAtIndex:index];
        [(UITableViewCell *)(recognizer.view) setAccessoryType:UITableViewCellAccessoryNone];
    } else { [selectedItems addObject:row];
             [(UITableViewCell *)(recognizer.view) setAccessoryType:UITableViewCellAccessoryCheckmark];

Just add NSMutableArray *selectedItems and NSArray *datasource to interface and you're ready to go.

comments powered by Disqus