Cocoa-Touch: UIPickerView viewForRow меняет порядок строк - PullRequest
0 голосов
/ 09 октября 2009

У меня есть UIPickerView. Я настраиваю его строки через viewForRow его делегата следующим образом:

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    if (view) {
        return view;
    } else {
        NSString *s = [datePickerValues objectAtIndex:row];

        UILabel *l = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 44)] autorelease];
//        l.text = s;
        l.text = [NSString stringWithFormat:@"%@ r:%ld", s, row];
        l.font = [UIFont boldSystemFontOfSize:18];
        l.textAlignment = UITextAlignmentCenter;
        l.backgroundColor = [UIColor purpleColor];
        return l;
    }
}

Когда я немного раскручиваю его, строки смешиваются.
Я даже получаю один и тот же ряд два или более раз, а иногда пропускаю ряды. Счетчик строк всегда равен 10 тыс., Он просто вызывает метод делегата viewForRow с неверным параметром row.

Я использую пареметр row для идентификации строк. (как сказано в документации). Он имеет один компонент, поэтому параметр component всегда равен 0, я проверял это с помощью отладчика.

Еще одна странная вещь, согласно документации, когда я создаю представление для конкретной строки, параметр делегата view будет иметь такое представление, но с помощью отладчика, который я видел, иногда вызывается viewForRow делегата. более одного раза для одной строки с view = nil.

Есть идеи, почему это странное поведение? Я новичок в какао и Obj-C, я делаю что-то не так?

EDIT:

Из документов:
view - Объект представления, который ранее использовался для этой строки, но теперь скрыт и кэширован представлением средства выбора.

Таким образом, это означает, что во второй раз, когда делегат viewForRow вызывается для конкретной строки, он будет иметь представление, возвращаемое при вызове 1. Это имеет смысл, так как в этом случае делегату не придется заново создавать представление снова и снова, когда пользователь вращает элемент управления.
Я убедился, что на самом деле viewForRow вызывается КАЖДЫЙ раз, когда отображается строка, даже если она отображалась ранее.

Что тогда использовать для параметра view? Два ответа пока не верны.

Ответы [ 3 ]

2 голосов
/ 09 октября 2009

Вы должны обновлять данные в представлении каждый раз, когда вызывается этот метод. Не обновляя, вы возвращаете устаревшие / дублированные данные.

1 голос
/ 09 октября 2009

Похоже, проблема в том, что UIPickerView пытается re использовать уже созданные представления для новых строк из соображений производительности. В этом случае ((view != nil)) вы просто возвращаете то же представление, которое вы имели для некоторой предыдущей строки. Если ваше мнение всегда UILabel, вы можете переписать свой код следующим образом (извините, не скомпилировал):

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    NSString *s = [datePickerValues objectAtIndex:row];

    UILabel *l = (view != nil)? view : [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 44)] autorelease];
    l.text = [NSString stringWithFormat:@"%@ r:%ld", s, row];
    l.font = [UIFont boldSystemFontOfSize:18];
    l.textAlignment = UITextAlignmentCenter;
    l.backgroundColor = [UIColor purpleColor];
    return l;
}

все должно работать нормально.

0 голосов
/ 19 мая 2014

Я вижу, что это очень старый вопрос, но у меня возникла та же проблема с iOS7, и я не смог найти удовлетворительного ответа. Когда я пытался получить доступ к параметру 'row' из метода делегата viewForRow, он возвращал неверные и перепутанные значения.

Я смог решить эту проблему, выполнив следующее,

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
...

    //Create a label
    //Set a tag for label
    //Add label to view as a subview
    //return view

 if (component == 1) {
    view = [[UIView alloc] init];
    view.backgroundColor = [UIColor clearColor];
    correctRowLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 30, 20)];
    [correctRowLabel setText:[NSString stringWithFormat:@"%li", row]];
    [correctRowLabel setTag:100];
    [view addSubview: correctRowLabel];
    return view;
  }

После того, как компонент настроен должным образом, в начале метода делегата viewForRow, выполните следующее, чтобы просмотреть правильные значения строки,

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {

    UILabel* correctRow = (UILabel*)[pickerView viewWithTag:100];
    NSInteger correctRowValue = [correctRow.text integerValue];
    NSLog(@"Correct row is: %li",correctRowValue);
    UILabel* correctRowLabel = nil;

...

РЕДАКТИРОВАТЬ:

Я хотел добавить, что для rowHeightForComponent должно быть установлено значение по умолчанию, а метка должна быть сброшена в верхней части метода viewForRow. Это не работает идеально, но это значительно лучше, чем раньше. Если я узнаю что-нибудь еще, я обновлю этот пост.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...