UIPickerView не сразу перерисовывает невыбранные строки

У меня есть специальный UIPickerView, где строки выбираются вручную, нажав на них. Когда это происходит, меняется стиль выбранной строки (меняется цвет текста и отображается изображение с галочкой). Аналогичным образом, если выбрана другая строка, ранее выбранная строка «отменяет выбор», т. е. ее стиль меняется на обычный.

Теперь, когда я выбираю строку, она выглядит правильно:

введите здесь описание изображения

Но когда я прокручиваю до другой строки, а выбранная строка больше не находится посередине, ее новый стиль не применяется (здесь следует выбрать Антарктис):

введите здесь описание изображения

Однако, если я прокрутлю несколько строк вниз, а затем вернусь, он обновит строку до ее правильного стиля:

введите здесь описание изображения

У меня такая же проблема при отключении. Если я выберу другую строку, старая строка, по-видимому, не будет отменена, и я получу это (сейчас Антарктида должна быть отменена):

введите здесь описание изображения

Но если я прокручиваю строку Антарктиды назад посередине, она действительно снимается. Итак, моя проблема в том, что UIPickerView не сразу перерисовывает строки, которые видны, но не в середине (вероятно, они каким-то образом кэшируются). Они перерисовываются только тогда, когда конкретная строка выходит из поля зрения, а затем возвращается, или когда отображаются совершенно новые строки.

Так могу ли я заставить его перерисовать эти строки? Я попытался вызвать метод setNeedsDisplay как для UIPickerView, так и для конкретных строк (которые являются подклассами UITableViewCell), но это ничего не дало.

Благодарю вас!


person pajevic    schedule 18.02.2015    source источник


Ответы (3)


Пробовали ли вы вызывать reloadComponent: или reloadAllComponents на своем экземпляре UIPickerView?

person fpg1503    schedule 18.02.2015
comment
Да, это не имело значения. Возможно, это связано с тем, что лежащие в основе данные на самом деле не меняются. - person pajevic; 18.02.2015
comment
Вы не обновляете свою модель? Как пометить строку как выбранную? - person fpg1503; 18.02.2015
comment
Модель просто используется для заполнения текста строк. Когда строка выбрана, ее данные используются для заполнения UILabel. Выбор запоминается самой строкой (т.е. подклассом UITableViewCell). PS. Проект достался мне в наследство от предыдущих разработчиков, поэтому не могу ответить, почему была выбрана именно эта реализация :) - person pajevic; 18.02.2015
comment
Ваш метод настройки строки должен отражать выбор, т. е. если вы используете viewForRow:forComponent:, вы должны проверить, следует ли выбирать эту строку, и соответствующим образом обновить пользовательский интерфейс, чтобы reloadAllComponents работал, и вы не потеряете выбор, когда строка исчезнет с экрана. . - person fpg1503; 18.02.2015
comment
На самом деле, я только что еще раз проверил их метод viewForRow:forComponent:, и он действительно отражает выбор. Не на модели, а на возвращаемом представлении. Кроме того, как я уже сказал, выбор действительно проходит - если я прокручиваю выбранную строку в середине средства выбора. Просто не перерисовывается для рядов, которые не посередине, но все же видны. - person pajevic; 18.02.2015
comment
Сукин сын... Звонок reloadAllComponents действительно сработал. Просто класс был в отдельном фреймворке, поэтому его нужно было очистить :) - person pajevic; 18.02.2015
comment
Однако вызов reloadAllComponents имеет побочный эффект. Моя выбранная строка теряет свою позицию, т. е. средство выбора прокручивается до первого элемента. Любая идея, как предотвратить это? - person pajevic; 18.02.2015

Я публикую свой ответ здесь, чтобы объяснить, что я сделал в качестве обходного пути для побочного эффекта при использовании reloadAllComponents, как это было предложено fpg1503 в его ответе.

В основном я помню выбор, а затем программно устанавливаю его снова после завершения reloadAllComponents:

    // We tell the picker to reload data in order to force it to redraw all rows.
    // Otherwise it may look like multiple rows are selected as checkmarks from previously selected row remains visible.
    // When reloading data the picker will automatically scroll to first row. That's why we will make it to go to the selected row afterwards.
    NSInteger selectedIndex = [self.countryCodePicker selectedRowInComponent:0];
    [self.countryCodePicker reloadAllComponents];
    // We have to make the selection with a delay, otherwise it may perform it before reloading was finished.
    double delayInSeconds = 1.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [self.countryCodePicker selectRow:selectedIndex inComponent:0 animated:NO];
    });
person pajevic    schedule 26.08.2015

@NobleK Спасибо за быстрый ответ! Я попробовал ваше решение, но обнаружил, что визуальное перемещение сборщика вперед и назад отвлекает - ОДНАКО... Это дало мне отличную идею: проблема на самом деле не в том, что вызов reloadAllComponents вызывает прыжок - это кран, который проходит через распознаватель жестов, который сбивает с толку после перезагрузки. Итак... что я сделал, так это поместил вызов перезагрузки в синхронизированную отправку и вуаля! Работает отлично! :-D

// delay the reload slightly
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
{
    [self.pickerView reloadAllComponents];
});
person Zack Black    schedule 26.08.2015