11

I'm trying to use a UIPicker View with a behavior somehow different of what's usually seen in iPhone code examples.

What I want to do is to allow users to scroll through the picker contents, but not to select a picker's row automatically (using the "didSelectRow" method from picker's delegate). Instead, I want to allow the user to touch the center row of the picker, which gets highlighted, and becomes the selection.

Is there any way to achieve this?

Thanks in advance.

camilo
  • 1,451
  • 3
  • 20
  • 31
  • Can you explain better why the didSelectRow method doesn't help you here? Have you tried using it and if so what problem did you have? –  Mar 08 '10 at 18:06
  • The problem is that it works like it supposes to. :-/ Basically i've seem a pickerView where the picker did's select automatically one of it's row values, but it only selects a value when the user touches it. I was trying to do the same but I couldn't. – camilo Mar 09 '10 at 14:31

5 Answers5

15

Add a gesture recogniser to the UIPickerView which triggers a target method in your object:

myGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pickerTapped:)];
[myPicker addGestureRecognizer:myGR];

// target method

-(void)pickerTapped:(id)sender
{
// your code
}
  • Martin, I happened upon your solution and found it very helpful. So simple and it works. The only issue, in my response to the tap, how can I pass the tap through to the picker so that I get the object at the line that is tapped, not the object at center? – Dean Davids Jan 08 '12 at 13:47
  • 7
    @DeanDavids It seems the page you've pointed doesn't exist any more. Could you provide another one, or explain the solution? – Grzegorz D. Mar 01 '13 at 11:46
  • To any googlers who find this answer, there is another stackoverflow answers that handles allowing a click to passthrough and select an item - https://stackoverflow.com/a/25719326/655822 – jp36 Nov 08 '17 at 17:31
5
  1. make a new UIControl

    • same position as the UIPickerView
    • [yourcontrol setBackGroundColor: [UIColor clearColor]];
  2. make a method

- (IBAction) pickerControlTapped 
{
    [yourpicker selectRow: rand()% yourpickersize
              inComponent: 0
                 animated: YES];
}

.3. make a connection between 1 and 2

 
[yourcontrol addTarget: self 
                action: @selector(pickerControlTapped) 
      forControlEvents: UIControlEventTouchUpInsied];
Joey
  • 2,912
  • 2
  • 27
  • 32
  • Excellent, please mark this as answer. Note: make it the same position as the center row of the UIPickerView. – Jared Thirsk Dec 21 '11 at 05:53
  • I think this is simple and brilliant. Since the selecting row height is already known, it can be positioned precisely and simply. Great stuff, thanks. – Roddy Feb 12 '14 at 04:07
  • Sorry, I just have to say again how excellent this solution is, has made my afternoon. – Roddy Feb 12 '14 at 04:23
2

Building on Martin Linklater's answer to support tapping on the pickers other rows: Has some magic numbers but works for me.

- (void) pickerTapped:(UITapGestureRecognizer*)gestureRecognizer
{
    CGPoint location = [gestureRecognizer locationInView:self.pickerView];

    CGFloat halfViewHeight = self.pickerView.frame.size.height / 2;

    NSInteger row = -1;
    if (location.y < halfViewHeight - 22
        && location.y > halfViewHeight - 66)
    {
        row = [self.pickerView selectedRowInComponent:0] - 1;
    }
    else if (location.y < halfViewHeight + 22
             && location.y > halfViewHeight - 22)
    {
        row = [self.pickerView selectedRowInComponent:0];
    }
    else if (location.y < halfViewHeight + 66
             && location.y > halfViewHeight + 22)
    {
        row = [self.pickerView selectedRowInComponent:0] + 1;
    }

    if (row >= 0 && row < [self.content count])
    {
        id element = [self.content objectAtIndex:row];

        if (element)
        {
            [self.pickerView selectRow:row inComponent:0 animated:YES];

            // do more stuff
        }
    }
}
richy
  • 2,716
  • 1
  • 33
  • 42
  • To any googlers who find this answer, there is another stackoverflow answer that handles allowing a click to passthrough and select an item without having to rely on magic numbers - https://stackoverflow.com/a/25719326/655822 – jp36 Nov 08 '17 at 17:32
1

I have a relatively simple solution to this problem that has worked well for me. Using a hidden custom button you can achieve the tap functionality without a gesture recogniser. This solution works for a picker with one component, however I'm sure it could be adapted to work with more.

Firstly add a button, either in the Interface Builder or programatically. Make it hidden and as wide as the picker then place it so that it sits exactly in the centre of the picker and also in front of it in the view hierarchy.

I'm using an IBAction like this to show my picker. However it's really up to you how you show and hide the picker.

- (IBAction)showPicker:(id)sender
{
    _picker.hidden = NO;
    _buttonPicker.hidden = NO;
}

All the action for choosing the picker value happens in an IBAction for the UIControlEventTouchUpInside event, something like this.

- (IBAction)selectPicker:(id)sender
{
    //Hide the button so that it doesn't get in the way
    _buttonPicker.hidden = YES;

    //Make sure we're within range
    NSInteger max = _values.count;
    NSInteger row = [_picker selectedRowInComponent:0];
    if(row >= 0 && row < max) {
        NSString *value = [_values objectAtIndex:row];

        //Set the label value and hide the picker
        _label.text = value;
        _picker.hidden = YES;
    }
}

I've slightly modified the code for this answer from working code so apologies if it's broken at all.

SHaKie
  • 1,414
  • 1
  • 10
  • 11
0

There are only 2 delegates for UIPickerView.

So, we can use only 7 methods to control UIPickerView by delegate.

– pickerView:rowHeightForComponent:
– pickerView:widthForComponent:
– pickerView:titleForRow:forComponent:
– pickerView:viewForRow:forComponent:reusingView:
– pickerView:didSelectRow:inComponent:
– numberOfComponentsInPickerView:
– pickerView:numberOfRowsInComponent:

that'all.

In UITableViewDelegate case, there are more methods for UITableView for managing selections. such as, – tableView:willSelectRowAtIndexPath:
– tableView:didSelectRowAtIndexPath:
– tableView:willDeselectRowAtIndexPath:
– tableView:didDeselectRowAtIndexPath:

However...

In UIPickerViewDelegate case, there is only 1 method for responding to row selection.

– pickerView:didSelectRow:inComponent:

Joey
  • 2,912
  • 2
  • 27
  • 32
  • that's what I was thinking. I've seen applications doing what I want, but I suppose i'm doing it some other way. Thanks anyway. – camilo Mar 09 '10 at 10:12