Обновление высоты UITableView при загрузке твита

У меня есть UITableViewCell который содержит TWTRTweetView с автоматической разметкой. Я загружаю твит, как это:

Ограничения

Высота детали

- (void)loadTweetWithId:(NSString *)tweetId {

    if (mTweetId == nil || ![mTweetId isEqualToString:tweetId]) {
        mTweetId = tweetId;
        [[[TWTRAPIClient alloc] init] loadTweetWithID:tweetId completion:^(TWTRTweet *tweet, NSError *error) {
            if (tweet) {
                NSLog(@"Tweet loaded!");
                [mTweetView configureWithTweet:tweet];
                [mTweetView setShowActionButtons:YES];
                //[mTweetView setDelegate:self];
                [mTweetView setPresenterViewController:self.viewController];
                [mTweetView setNeedsLayout];
                [mTweetView layoutIfNeeded];
                [mTweetView layoutSubviews];
                hc.constant = mTweetView.frame.size.height;
                [self updateConstraints];
                [self layoutIfNeeded];
                [self layoutSubviews];
                [self.tableView setNeedsLayout];
                [self.tableView layoutIfNeeded];
                [self.tableView layoutSubviews];
            } else {
                NSLog(@"Tweet load error: %@", [error localizedDescription]);
            }
        }];
    }
}

Когда загруженная в твиттере ячейка не изменится, пока я не выделю ее и не вернусь назад. Я попробовал несколько подходов, как вы можете видеть в фрагменте кода. Но не из этих работ. Мое табличное представление использует полностью автоматический подход макета, который не реализует высоту ячейки для функции строки. Как я могу это исправить?

ОБНОВИТЬ:

С помощью:

[self.tableView beginUpdates];
[self.tableView endUpdates];

невозможно, потому что, когда я делаю это, происходит перерисовка всех ячеек и очень большие прыжки, и это недопустимо. Также я подтвердил, что блок завершения твита работает в основном потоке.

Перейти видео

ОБНОВЛЕНИЕ 2:

Я также пытался кэшировать твит-представление с помощью твит-идентификатора и перезагружать ячейку для связанного индекса, а также давать такое же твит-представление для твит-идентификатора. Высота ячейки исправлена, но она не становится видимой до прокрутки.

ОБНОВЛЕНИЕ 3:

Я даю ограничения для просмотра твита в xib ячейки, и ограничение по высоте связано. Так что это не главная проблема темы. Я также упомянул, что перезагрузка определенной ячейки по индексу не работает.

Работая над другим решением, я видел пример TwitterKit коды, которые используют TWTRTweetTableViewCell но загружал твиты для настройки ячеек. Итак, я сделал то же самое. Это обходной путь, конечно.

3 ответа

Обновленный ответ:

Вы делаете неправильно несколько вещей, которые могут вызвать (или, по крайней мере, способствовать) прыжки:

  • Никогда не звони layoutSubviews сам. Это метод, вызываемый системой для разрешения ваших ограничений. Это автоматически срабатывает при звонке setNeedsLayout а также layoutIfNeeded в ряд.

  • То же самое относится и к updateConstraints , Он вызывается системой во время прохода макета. Вы можете вручную вызвать его, впоследствии позвонив setNeedsUpdateContraints а также updateConstraintsIfNeeded, Кроме того, он действует только в том случае, если вы фактически реализовали (переопределили) этот метод в своем пользовательском представлении (или ячейке).

  • Когда вы звоните layoutIfNeeded на вид он размещает свои подпредставления. Таким образом, когда вы изменяете константу ограничения, которое ограничивает ваш mTweetView, это, вероятно, не будет иметь никакого эффекта (если иерархия представления недействительна во время запуска триггера). Вам нужно позвонить layoutIfNeeded на mTweetView superview, которое является представлением содержимого ячейки (судя по скриншоту, который вы добавили в свой пост):

    [contentView layoutIfNeeded];
    

Кроме того, есть еще одна вещь, о которой вам нужно знать, которая также может вызвать мерцание:

  • Клетки в табличном представлении перерабатываются. Каждый раз, когда ячейка используется повторно, вы загружаете новый твит. Я предполагаю, что это из асинхронного сетевого запроса? Если это так, существует вероятность того, что блок завершения из первого твита, загруженного для этого экземпляра ячейки, вернется после блока завершения из второго твита, загруженного для этой (переработанной) ячейки, когда вы выполняете прокрутку очень быстро или ваше интернет-соединение очень медленное, Убедитесь, что вы отменили запрос или аннулировали его, когда ваша ячейка используется повторно (prepareForReuse метод).

Пожалуйста, убедитесь, что вы исправили все эти проблемы, и посмотрите, работает ли анимация так, как ожидалось. (Мой оригинальный ответ ниже остается в силе.)


Оригинальный ответ:

Я уверен, что

[self.tableView beginUpdates];
[self.tableView endUpdates];

это единственный способ автоматически изменить размер ячейки при отображении.

Причина:

По историческим причинам и причинам производительности UITableView всегда работает с ячейками фиксированной высоты (внутренне). Даже при использовании самоконтроля ячеек путем установки estimatedRowHeight и т. д. табличное представление будет вычислять высоту ячейки, когда она снята, то есть до того, как она появится на экране. Затем он добавит некоторые внутренние ограничения в ячейку, чтобы придать ей фиксированную ширину и фиксированную высоту, которые просто соответствуют размеру, вычисленному Auto Layout.

Эти внутренние ограничения обновляются только при необходимости, то есть при перезагрузке строки. Теперь, когда вы добавляете какие-либо ограничения внутри вашей ячейки, вы будете "бороться" с этими внутренними ограничениями, которые имеют требуемый приоритет (также известный как 1000). Другими словами: победить невозможно!

Единственный способ обновить эти внутренние (фиксированные) ограничения ячеек - сообщить табличному представлению, что оно должно. И насколько я знаю, единственный публичный (документированный) API для этого

- (void)beginUpdates;
- (void)endUpdates;

Итак, единственный вопрос, который остается:

Почему этот подход не вариант для вас?

Я думаю, что законно перерисовать ячейку после того, как она была изменена. Когда вы расширяете ячейку, чтобы показать более длинный твит, чем прежде, ячейка все равно должна быть перерисована!

Вы, вероятно, не будете (и не должны) изменять размер всех видимых ячеек все время. (Это было бы довольно запутанным для пользователя...)

У меня была похожая проблема, и я исправил ее, добавив весь свой код в dispatch_async, чтобы убедиться, что он работает в главном потоке.

 dispatch_async(dispatch_get_main_queue(), ^{ 
      /*CODE HERE*/
 });

Итак, ваш код должен быть таким:

- (void)loadTweetWithId:(NSString *)tweetId {

  if (mTweetId == nil || ![mTweetId isEqualToString:tweetId]) {
      mTweetId = tweetId;
    [[[TWTRAPIClient alloc] init] loadTweetWithID:tweetId completion:^(TWTRTweet *tweet, NSError *error) {

        dispatch_async(dispatch_get_main_queue(), ^{ 

        if (tweet) {
            NSLog(@"Tweet loaded!");
            [mTweetView configureWithTweet:tweet];
            [mTweetView setShowActionButtons:YES];
            //[mTweetView setDelegate:self];
            [mTweetView setPresenterViewController:self.viewController];
            [mTweetView setNeedsLayout];
            [mTweetView layoutIfNeeded];
            [mTweetView layoutSubviews];
            hc.constant = mTweetView.frame.size.height;
            [self updateConstraints];
            [self layoutIfNeeded];
            [self layoutSubviews];
            [self.tableView setNeedsLayout];
            [self.tableView layoutIfNeeded];
            [self.tableView layoutSubviews];
        } else {
            NSLog(@"Tweet load error: %@", [error localizedDescription]);
        }

    });

    }];
  }
 }

Попробуйте перезагрузить эту конкретную ячейку, после того как вы загрузили твит, используя,

- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths 
              withRowAnimation:(UITableViewRowAnimation)animation;
Другие вопросы по тегам