1

The UIPickerView class has a method selectedRowInComponent that returns the selected row for the component. That may or may not be the item that is in the center of the picker view. What I'd like is to be able to tell what index of the pickerView data is currently being displayed (not selected).

To illustrate the difference, if you tap a value in the UIPickerView dial, the row for that value seems to always be returned in selectedRowInComponent. However, if the user scrolls the picker through several values and then lifts the finger, selectedRowInComponent is not updated, or it is updated to the value that just scrolled off.

Is there anyway to determine where the picker component is actually dialed?

The value is always available in method pickerView:didSelectRow:inComponent: but I would like to query it in method pickerView:titleForRow:forComponent:

Why? Because while the UIPickerView is being scrolled selectedRowInComponent is not being called. If for some reason I get to the end of the data and need to add more, I need to do it in a method that is being called. That would seem to be pickerView:titleForRow:forComponent:, which is called for every row.

Victor Engel
  • 2,037
  • 2
  • 25
  • 46
  • You may not get the exact value while the dial is spinning, but once it stops you should always get the correct value through the `selectedRowInComponent`. You know that the dial has stopped when the `pickerView:didSelectRow:inComponent:` method of the delegate gets called. – Sergey Kalinichenko Jan 14 '13 at 21:14
  • 1
    @dasblinkenlight, true, but I need the value before then. I've modified the question to be more specific. – Victor Engel Jan 14 '13 at 21:31
  • Victor, your statement "That may or may not be the item that is in the center of the picker view." is wrong. PickerView always returns the row which is in the center and that is the selected row. Are you talking about a pickerview which has more than one component and you are wondering about the row in the other component. Can you please show a picture of your screen shot and elaborate. – Srikanth Jan 14 '13 at 21:36
  • 1
    @Srikanth, you are correct for method `pickerView:didSelectRow:inComponent:` but not for method `pickerView:titleForRow:forComponent:` as I stated in my edit. I'll be happy to add a screen print after I figure out how to add it here. – Victor Engel Jan 14 '13 at 21:40
  • If you are going to "load more", how are you planning to deal with the number of rows in component? It's certainly going to change as the result of loading more data; how are you planning to tell the component that you've got more rows as the component is being scrolled? – Sergey Kalinichenko Jan 14 '13 at 21:43
  • 1
    Add more to one end. Remove from other end. Update row. Same number of rows. – Victor Engel Jan 14 '13 at 21:48
  • Victor, is there any reason you are doing what you are suggesting. You are trying to implement the functionality provided by a UIKit control yourself. If you already have an array of say 50 entries, and 5 rows are visible at any time, you need not do any thing. The system will automatically show the data. All you need to do is some thing like this "-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{ return [NSString stringWithFormat:@"%d",row]; } – Srikanth Jan 14 '13 at 21:54
  • You can see that the rows will show numbers as many as you want. Replace the "return" statement with what you have in your data model. – Srikanth Jan 14 '13 at 21:55
  • 1
    @Srikanth, yes I have a good reason. I don't know what range of values the user is likely to want to use. Take the UIDatePicker class as an illustration of something similar that is limited by design. The earliest possible year that can be selected with the Gregorian calendar is year 1. What if you are building something that requires entry of dates BC? Then you can't use UIDatePicker. That's an artificial limitation that isn't really necessary, in my opinion. – Victor Engel Jan 14 '13 at 21:58
  • 1
    @Srikanth, I have no idea what you are saying in your second comment. Can you rephrase? Certainly, it's possible to add rows going forward indefinitely, but if a user is scrolling the opposite direction, back past the start of the array, then what? – Victor Engel Jan 14 '13 at 22:00
  • Victor, that was for cases where you had finite data. Looks like you have a complicated problem. Not sure how I would solve it. I was saying that if you had a data model, you can say "return [myDataModel objectAtIndex:row]"; But based on what you are suggesting, you want to do some thing additional. – Srikanth Jan 14 '13 at 22:13
  • 1
    I think that for now I'll use a kludge. The user will always have a starting point. I will populate the picker values for +/- 1000 items relative to the current data. If the user needs to go further, they can select data within 1000 items and start the process again, at which point a new set of data will be gathered. This doesn't answer my question, but it does get the app to be functional. – Victor Engel Jan 14 '13 at 22:19

1 Answers1

1

I know this question is a bit old, but by answer it I could help someone else.

I think I found a solution to this problem you had.


Solution

- (NSString *)pickerView:(UIPickerView *)pickerView
         titleForRow:(NSInteger)row
        forComponent:(NSInteger)component
{
    // Passing the row being viewed to a function that does something with it.
    [self handleRowBeingViewed:[pickerView selectedRowInComponent:component]];
}

- (void)pickerView:(UIPickerView *)pickerView
      didSelectRow:(NSInteger)row
       inComponent:(NSInteger)component
{
    // Passing the row being viewed to a function that does something with it.
    [self handleRowBeingViewed:[pickerView selectedRowInComponent:component]];
}

/**
 * It receives, in input 'rowBeingViewed', the row being viewed by the user in the center of the picker view, and use it to XYZW... 
 *
 *
 * @param rowBeingViewed     Row currently being viewed by the user in the center of the picker view.
 * @return
 */
- (void) handleRowBeingViewed:(NSInteger)rowBeingViewed
{
     // Printing for debugging.
     NSLog(@"String Being Viewed: %@", pickerViewArray[rowBeingViewed]);

     // DO YOUR STUFF HERE
     // ...
}

Explanation

The UIPickerView allows you to know which row is selected (or viewed in the center, which I think is the same) at any time by using the method selectedRowInComponent.

If you use that method selectedRowInComponent inside the delegate's method pickerView:titleForRow:forComponent, you can know which row is being viewed in the center every time a new title is being "printed" to the user in the picker view.

Sometimes, if in the Picker View you scroll only 1 or 2 rows, the delegate's method pickerView:titleForRow:forComponent does not get called and you won't know which row is being viewed in the center. To solve that, also use the same method selectedRowInComponent inside the delegate's method pickerView:didSelectRow:inComponent:.

Hope this helps someone.

jmoukel
  • 794
  • 6
  • 18