Search code examples
iosios8uipickerviewuipickerviewdelegate

Can't get UIPicker text coloring to stick


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?


Solution

  • @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];
    ...