2015-05-07 3 views
10

У меня есть UITableView с ячейкой с динамическим размером, чтобы она соответствовала UITextView внутри. Всякий раз, когда вводится ключ, ячейка проверяет, увеличилась ли подсчитанная высота, как и в новой строке, поэтому она может указать таблице, что высота ячейки должна быть пересчитана. Я делаю это с помощью этого кода.UITableView Scrolls to Top on Cell Refresh

- (void) createNoteCellViewDidUpdate: (CreateNoteCell*) cell { 

    CGFloat newHeight = [self tableView:self.tableView heightForRowAtIndexPath:CreateNoteCellIndexPath]; 
    if (newHeight != CGRectGetHeight(cell.contentView.frame)) { 
     [self.tableView beginUpdates]; 
     [self.tableView endUpdates]; // <- HERE IS WHERE THE CONTENT OFFSET CHANGES 
    } 
} 

Оценки размера и стола как ожидалось. Но вместо того, чтобы просто оживлять изменение высоты, он также прокручивается вверх. Это можно увидеть здесь, нажав клавишу возврата.

table scrolling on cell resize

По Key Value Наблюдающий, я обнаружил, что вид прокрутки contentOffset создается, когда contentSize меняет взгляд скроллинга. И что contentSize меняет много раз, когда вызывается метод endUpdates. Когда он меняется, он идет от нормальной высоты, до довольно большой высоты, а затем возвращается к нормальной высоте. Интересно, будет ли это из-за этого. Я не знаю, куда идти отсюда.

+0

Вопрос: почему вы пытаетесь изменить размер табличного представления, а не просто изменять размер ячейки? Обычно рамка tableview остается постоянной и изменяется контент. – Frankie

+1

Нет, я не трогаю рамку или рамки таблицы.Я изменяю размер ячейки, сообщая табличному представлению пересчитать все высоты ячеек. – Jadar

ответ

22

Вау, ответ Джош Gafni помогли много; он заслуживает продолжения. Мое решение основано на его. Это все еще похоже на хак, поэтому, если у кого-то еще есть лучший способ сделать это, мне все равно очень интересно это услышать.

Сначала я сохраняю смещение содержимого, затем запускаю обновление.

CGPoint offset = self.tableView.contentOffset; 
[self.tableView beginUpdates]; 
[self.tableView endUpdates]; 

Это анимирует изменение высоты ячейки и регулирует все кадры в соответствии с ограничениями.

Далее я удаляю все анимации из слоя tableView, поэтому анимация на вершине останавливается. Затем я возвращаю contentOffst к тому, чем он был раньше.

[self.tableView.layer removeAllAnimations]; 
[self.tableView setContentOffset:offset animated:NO]; 

Наконец, я позволил Tableview обрабатывать анимированные прокрутки вниз, чтобы в нижней части ячейки справа над клавиатурой.

[self.tableView scrollToRowAtIndexPath:CreateNoteCellIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; 

И вуаля, это работает очень хорошо.

fixed cell resize

+0

У меня была почти такая же проблема, но до сих пор не удавалось заставить это решение работать. Мне было интересно, вы делаете что-нибудь, чтобы убедиться, что ваша ячейка UITextView отображается над клавиатурой (например, обновляет содержимое)? Кроме того, нашли ли вы какие-либо улучшения в этом решении? Благодаря! – Stoph

+0

СПАСИБО, только то, что мне нужно. –

+0

Действительно приятное решение, спасибо Josh и Jadar – Atrash

7

Просто догадка ...

Сохранить contentOffset в UITableView до каких-либо изменений. Затем установите его снова.

CGFloat contentOffset = self.tableView.contentOffset; 

, а затем после изменения

self.tableView.contentOffset = contentOffset; 
+0

Да, но это проблема, когда contentOffset задается ScrollView, а затем устанавливается мной. Таким образом, анимация начинает выводить ее на первое место, затем я прихожу в середине анимации и возвращаю ее обратно. Таким образом, он анимируется, а затем вниз, что становится очень раздражающим после того, как высота занимает весь экран. – Jadar

+1

Одна мысль (немного взлома) может заключаться в подклассе tableView и перезаписывать 'setContentOffset'. 'contentOffset' должен быть установлен в 0 в какой-то момент для перехода. Добавьте свойство bool в табличное представление, называемое 'isUpdatingCellHeight', и только тогда, когда эта переменная' NO' действительно обновляет '_contentOffset'. Поэтому перед обновлением таблицы установите значение «YES» и установите значение «NO», а затем установите «contentOffset», как я упоминал выше. –

+0

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

3

Более упрощенное решение (добавить Извещение наблюдателя при TextView изменен), Свифт-версия. Основной трюк - UIView.setAnimationsEnabled.

func textViewDidChanged(notification: NSNotification) { 
    UIView.setAnimationsEnabled(false) 

    let contentOffset = self.tableView.contentOffset 

    tableView.beginUpdates() 
    tableView.endUpdates() 

    tableView.contentOffset = contentOffset 

    UIView.setAnimationsEnabled(true) 
} 
+0

Интересно, я не знал, что этот метод существует. Благодаря! – Jadar

+0

@Jadar, спасибо, если этот метод работает и упрощает это оригинальное решение, отметьте его как ответ. Если бы это было полезно, вы можете хотя бы проголосовать за него, чтобы другие пользователи могли его легко найти. – Vasily

+0

У меня сейчас нет средств для тестирования, так как я больше не использую этот бит интерфейса. Я был бы более склонен это делать, если бы у вас было больше комментариев, объясняющих, как принятый в настоящее время ответ. – Jadar

7

Это мое расширение UITableView, которое прекрасно работает. В Swift 2.1. На основании принятого ответа.

extension UITableView 
{ 
    func reloadDataAnimatedKeepingOffset() 
    { 
     let offset = contentOffset 
     UIView.setAnimationsEnabled(false) 
     beginUpdates() 
     endUpdates() 
     UIView.setAnimationsEnabled(true) 
     layoutIfNeeded() 
     contentOffset = offset 
    } 
} 
+0

просто потрясающе! Благодаря!!!! – Potajedehabichuelas