Подтвердить что ты не робот

UITableView мерцает/заикается при вводе текста при автоматическом изменении размера TextView

В настоящее время у меня есть UITableView с изменением размера UITextView. Ячейка автоматически изменяет размер, используя beginUpdates/endUpdates, но когда он делает это, просмотр таблицы заикается (см. Ниже gif).

Конечным результатом является UITableViewCell, у которого есть текстовое представление, которое изменяет размер на основе его содержимого. Вот код внутри пользовательского класса UITableViewCell, который заставляет UITableView обновлять себя.

- (void)textViewDidChange:(UITextView *)textView {
    // This is a category on UITableViewCell to get the [self superView] as the UITableView
    UITableView *tableView = [self tableView];
    if (tableView){
        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

Вот что я уже пробовал:

Получить текущий contentOffset и сбросить его после endUpdates, но не работать Отключение прокрутки на UITableView перед обновлениями и последующее включение впоследствии Я пробовал возвращать NO всегда из - (BOOL)textViewShouldEndEditing:(UITextView *)textView Моя высота ячейки UITableView использует UITableViewAutomaticDimension. Любые другие идеи или мысли приветствуются.

Вот пример того, как он выглядит:

Table View Stutter

Я не хочу использовать какие-либо библиотеки, поэтому, пожалуйста, никаких предложений для этого.

Спасибо

Изменить: решение

Найдено здесь: Я не хочу, чтобы анимация начала обновления, конец блока обновлений для uitableview?

Кредит @JeffBowen для отличной находки (хотя хакки он работоспособен и позволяет мне по-прежнему внедрять методы UITableViewDelegate для поддержки iOS 7). Отключите анимацию до выполнения обновления, а затем включите после обновления, чтобы предотвратить UITableView от заикания.

[UIView setAnimationsEnabled:NO];
[tableView beginUpdates];
[tableView endUpdates];
[UIView setAnimationsEnabled:YES];

Если вам не нужно использовать методы Delegate и хотите использовать менее хакерское решение для iOS 8+, тогда перейдите к ответу @Massmaker ниже.

4b9b3361

Ответ 1

Мое решение (для iOS 8) было впервые установлено в моем представленииController viewDidLoad

self.tableView.rowHeight = UITableViewAutomaticDimension;
// this line is needed to cell`s textview change cause resize the tableview`s cell
self.tableView.estimatedRowHeight = 50.0;

затем, объединив эту статью решение в Swift и некоторые грязные мысли Я установил в своей ячейке свойство, называемое

@property (nonatomic, strong) UITableView *hostTableView;

и в ячейке -(void) textViewDidChange:(UITextView *)textView

 CGFloat currentTextViewHeight = _textContainer.bounds.size.height;
CGFloat toConstant = ceilf([_textContainer sizeThatFits:CGSizeMake(_textContainer.frame.size.width, FLT_MAX)].height);
if (toConstant  >  currentTextViewHeight)
{
    [_hostTableView beginUpdates];
    [_hostTableView endUpdates];
}

то в viewController

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

textCell.hostTableView = self.tableView;

after height change

Ответ 2

Просто отключите анимацию перед вызовом beginUpdates и снова включите ее после вызова endUpdates.

[UIView setAnimationsEnabled:NO];
[tableView beginUpdates];
[tableView endUpdates];
[UIView setAnimationsEnabled:YES];

Определенно взломать, но работает пока. Благодарим моего друга Бо, который указал мне на этот.

Ответ 3

Я не нашел способ добиться этого, потому что: Когда вы запускаете [endViews таблицы tableView], таблица пересчитывает contentSize и повторно устанавливает его. И это приведет к сбросу значения contentOffset по умолчанию.

Это поведение, унаследованное от UIScrollView, и я попытался его избежать:

  • Подклассификация UITableView и переопределение функций setContentOffset: и setContentOffset:animated. Но они не вызывают, когда table view меняет contentSize.
  • Подкласс UITableView, переопределение функции setContentSize: и настройка contentOffset на старое значение после обновления содержимого, но это не работает для меня
  • с помощью KVO и установкой старого значения для contentOffset сразу после него reset, но в любом случае у меня есть эта анимированная проблема.
  • настройка scrollEnabled для NO и scrollToTop для NO, но также не помогает

Если кто-нибудь найдет решение для этой проблемы, добро пожаловать. Возможно, это возможное решение - отключить автоматическое отключение: iOS: setContentSize заставляет весь кадр UIScrollView перейти

UPDATE: Я нахожу решение: прямое изменение высоты ячейки, размера содержимого и смещения содержимого: Это работает для меня (представление таблицы является делегатом ячейки UITextView)

- (void)textViewDidChange:(UITextView *)textView
{
    CGFloat textHeight = [textView sizeThatFits:CGSizeMake(self.width, MAXFLOAT)].height;
    if (self.previousTextHeight != textHeight && self.previousTextHeight > 0) {
        CGFloat difference = textHeight - self.previousTextHeight;
        CGRect cellFrame = self.editedCell.frame;
        cellFrame.size.height += difference;
        self.editedCell.frame = cellFrame;
        self.contentSize = CGSizeMake(self.contentSize.width, self.contentSize.height + difference);
        self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + difference);
    }
    self.editedNote.comments = textView.text;
}

Ответ 4

В Textview делегат изменения значения используйте этот код, чтобы изменить размер отдельной ячейки без каких-либо мерцаний и все такое. Но перед этим убедитесь, что вы использовали динамическую высоту ячейки таблицы.

UIView.setAnimationsEnabled(false)
DispatchQueue.main.async {
   self.tableView.beginUpdates()
   self.tableView.endUpdates()
   self.tableView.layer.removeAllAnimations()
}
UIView.setAnimationsEnabled(true)