edie edie - 9 months ago 74
Objective-C Question

UIPickerView: last value followed by first value

Can anyone help me how to make the UIPickerView displays the first row's value after the last row's value, just like the UIDatePicker where after 12 the 1 will follow.


Answer Source

I don't think its possible to really make it circular, but you can fake it.

#define kRowsInPicker 10000

- (void)viewDidLoad {
    NSArray *localPickerData = [[NSArray alloc] initWithObjects:
                                @"Ottawa", @"Toronto", @"Montreal", @"Winnipeg",
                                @"Saskatchewan", @"Iqaluit", @"Edomonton", nil];
    [self setPickerData:localPickerData];
    [localPickerData release];

    UIPickerView *localPicker = [[UIPickerView alloc] initWithFrame:
                                 CGRectMake(0, 0, 320, 216)];
    [localPicker setDelegate:self];
    [localPicker setDataSource:self];
    localPicker.showsSelectionIndicator = YES;
    NSInteger  selectedRow = 0;
    [localPicker selectRow:(((NSInteger)((kRowsInPicker / 2) / [pickerData count])) * [pickerData count]) + (selectedRow%[pickerData count]) inComponent:0 animated:NO];
    [self setPicker:localPicker];
    [localPicker release];

    [[self view] addSubview:picker];
    [super viewDidLoad];
#pragma mark -
#pragma mark UIPickerViewDataSource methods

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

- (NSInteger)pickerView:(UIPickerView *)pickerView
                                numberOfRowsInComponent:(NSInteger)component {
    // usually "return [pickerData count];"
    return kRowsInPicker; // 10,000 is good, if you add a few more zeros
                          // there seems to be problems.

#pragma mark -
#pragma mark UIPickerViewDelegate methods

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

You can change the number of strings in pickerData and it will still work fine. The selected row selects the "first" value closest to the middle. row%[pickerData count] returns the following assuming there are 3 NSStrings in pickerData:

ROW             RETURNS
 0                0
 1                1
 2                2
 3                0
 4                1
 5                2
 6                0
 7                1
 8                2
It will just cycle 0 through the length of the array. The confusing stuff in viewDidLoad just picks a value as close to the middle as possible using the index of the item of the array you provide in selectedItem. There is no performance hit or memory leak, all you have allocated is the single array. Whenever you access their selected choice, use ([localPicker selectedRowInComponent:0]%[pickerData count]). If there's something you don't understand or something I missed, please comment. Hope this helped!