Can't get UIPicker text coloring to stick

80 Views Asked by At

I'm trying to get a UIPicker that shows the selected row with green text. I use the pickerView:viewForRow:forComponent:reusingView: method to create a UILabel for it:

- (UIView*) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    UILabel *label = (UILabel*)view;
    if (label == nil) {
        label = [UILabel new];
        label.font = [UIFont boldSystemFontOfSize: 24];
        label.adjustsFontSizeToFitWidth = YES;
    }
    UIColor *color = (row == [pickerView selectedRowInComponent: component]) ? RGBx(0x579B2F) : UIColor.whiteColor;
    label.textAlignment = component == 0 ? NSTextAlignmentRight : NSTextAlignmentLeft;
    NSMutableAttributedString *string;
    if (component == 0) {
        string = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%3lu.", row]];
        [string addAttribute:NSForegroundColorAttributeName value: color range:NSMakeRange(0, string.length - 1)];
        [string addAttribute:NSForegroundColorAttributeName value: [UIColor clearColor] range:NSMakeRange(string.length - 1,1)];
    }
    else {
        string = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@".%02lu", row % 60]];
        [string addAttribute:NSForegroundColorAttributeName value: [UIColor clearColor] range:NSMakeRange(0,1)];
        [string addAttribute:NSForegroundColorAttributeName value: color range:NSMakeRange(1,string.length - 1)];
    }
    label.attributedText = string;
    return label;
}

There's some additional things in there, to get the two wheels aligned closely, but with a little bit of spacing (the transparent periods). It mostly works:

enter image description here

Initially, it looks perfect, green selections and white/gray others. The problem is that when I scroll the wheels, they don't always end up green. Sometimes they do, but not always. As can be seen, sometimes the scrolled value will stay green even if it's not selected anymore (see the 09 in the top right corner).

What do I do to keep the green only and always on the selected row?

2

There are 2 best solutions below

0
On BEST ANSWER

@idali diagnoses the problem well. And hints at what needs to happen. But didn't give the actual answer.

The answer is to use reloadComponent: (or reloadAllComponents). It should be done any time the user changes the selection, or you programmatically change the value. E.g.

-(void) pickerView:(UIPickerView*) pickerView didSelectRow:(NSInteger) row inComponent:(NSInteger) component {
    [pickerView reloadComponent: component];
}

and any time you use selectRow:inComponent:animated::

...
[self.picker selectRow: hours inComponent: 0 animated: YES];
[self.picker reloadAllComponents];
...
0
On

If a row was green initially, if you scroll up or down as far as this row is still visible it will keep the green color since viewForRow:(NSInteger)row forComponent: will not be called on that row (it will be called if this row was previously not visible and need to be visible)...

while you need in your selectedRowinCompoment to set green to selected you need also to remove green color from old selected row (in case it's still visible).