Запоминание позиции прокрутки в UITableView

У меня небольшая проблема с моим приложением iOS в xcode. У меня есть UITableView, который загружает несколько сотен ячеек. Когда я прокручиваю вниз до определенной ячейки, перехожу к подробным контроллерам просмотра и возвращаюсь снова, таблица основного представления полностью возвращается наверх. Я рассмотрел следующие 2 похожих вопроса.

Как получить UITableView положение прокрутки, чтобы я мог его сохранить?

Установка позиции прокрутки в UITableView

Я все еще не могу заставить их работать. Я не самый опытный программист, поэтому я действительно борюсь с этим.

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

В этой таблице у меня есть функция reloadData, поэтому можно получить последние данные с сервера, а также рабочую панель поиска.

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

Люк


person mylogon    schedule 17.09.2013    source источник
comment
Это не поведение по умолчанию. Похоже, что где-то в вашем коде вы прокручиваете вверх. Если вы удалите эту строку, все будет готово. Искать scrollToRowAtIndexPath возможно.   -  person Desdenova    schedule 17.09.2013
comment
ваша таблица прокручивается обратно наверх, когда она снова появляется в поле зрения, скорее всего, потому, что вы выполняете reloadData вызов в методе viewWillAppear: этого контроллера представления.   -  person Michael Dautermann    schedule 17.09.2013


Ответы (8)


Здесь вы должны сначала сохранить прокрученную позицию tableView, т.е. contentOffset из tableView, а затем повторно использовать ее, когда вы вернетесь к tableView.

1) Когда и где вы его сохраните:

Когда: когда вы переходите к detailViewController, сохраните contentOffset из tableView

Как: float verticalContentOffset = tableView.contentOffset.y;

2) Как вернуть tableView в то же положение прокрутки:

[tableView setContentOffset:CGPointMake(0, verticalContentOffset)];

Надеюсь, это поможет вам.

person Prashant Nikam    schedule 17.09.2013
comment
Есть идеи, как добиться этого для приложения для обмена сообщениями? Как и при прокрутке вверх, загружается больше строк, но текущее смещение Y всегда равно 0. Это означает, что установка contentOffset на Y = 0 просто прокручивает эту таблицу снова вверх. - person nhenrique; 13.08.2015

Сортировано!

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

[self.tableView setContentOffset:CGPointMake(0,-20) animated:NO];

По наивности я поставил это в viewDidAppear, а не в viewDidLoad. Очевидно, это скрыло панель поиска, но поскольку она была в неправильной команде void, она делала это каждый раз, когда masterDetailView возвращался на вершину стека. Итак, после перемещения приведенного выше кода в viewDidLoad он все еще скрывает его, но только один раз.

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

Спасибо всем за ваши идеи, которые помогли мне.

+1 всем вам!

person mylogon    schedule 17.09.2013
comment
Идеально. Спасибо. - person Baran Emre; 03.01.2018

Если кому-то интересно, я попробовал решение от Prashant N, и оно сработало. Однако reloadData на самом деле больше не сбрасывает положение прокрутки, поэтому мне не пришлось делать ничего, кроме reloadData.

person Enrico Susatyo    schedule 11.04.2016

Мое решение этой проблемы заключалось в прокрутке таблицы до строки индекса последнего элемента.

private func scrollToItem(item:Int, section:Int bottom:Bool = true, animated:Bool = false) {
    let indexPath = NSIndexPath(forRow: item:Int-1, inSection: section)
    var position = UITableViewScrollPosition.Bottom
    if (!bottom) { position = UITableViewScrollPosition.Top }
    self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: position, animated: animated)
}
person Guilherme Carvalho    schedule 09.09.2016

Почему-то для меня это было наполовину сработало (иногда положение было только приблизительным). В итоге я использовал следующее априори менее чистое решение

NSIndexPath *firstVisibleIndexPath = [[self.tableView indexPathsForVisibleRows] objectAtIndex:0];
[self.tableView scrollToRowAtIndexPath:self.firstVisibleIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
self.firstVisibleIndexPath = firstVisibleIndexPath;

который работал лучше.

person vib    schedule 25.01.2017
comment
Подход по довольно длинному маршруту, но должен хорошо работать. Почему вы сохраняете индексный путь как переменную экземпляра? Я полагаю, это что-то конкретное для вашего проекта? - person mylogon; 25.01.2017
comment
Ну, я думал, что отвечаю на что-то немного другое, это для варианта использования с сегментированным элементом управления и 2 сегментами. Поэтому, когда вы переключаете сегмент, вы сохраняете indexPath для следующего раза, когда вы перейдете к этому сегменту (обратите внимание, что свойство устанавливается после завершения прокрутки) - person vib; 25.01.2017
comment
Обновляет ли это firstVisibleIndexPath, когда вы остаетесь на экране и продолжаете играть с tableview, прокручивая его вверх и вниз? В каком методе события или делегата вы постоянно firstVisibleIndexPath обновляете при прокрутке таблицы? - person Hemant Bavle; 24.01.2019

Как упоминалось в других комментариях, прокрутка вверх на Back навигации в UINavigationController не является поведением по умолчанию.

Другая причина может заключаться в том, что вы устанавливаете ячейку в верхней части таблицы в качестве первого респондента в viewWillAppear, например поле поиска или поле редактирования в верхней части таблицы. UITableViewController будет автоматически прокручивать первого респондента в поле зрения, что приятно. Пока это то, что вы пытаетесь делать. :) Позаботьтесь о том, чтобы не указывать первого респондента в viewWillAppear, если вы этого не хотите. Ура, Аризона

person andyzei    schedule 04.05.2017

Мое решение для коллекции:

CGFloat oldCollectionViewHeight = self.messageCollectionView.contentSize.height;

[self.messageCollectionView reloadData];
[self.messageCollectionView layoutIfNeeded];

CGFloat newCollectionViewHeight = self.messageCollectionView.contentSize.height;

if (oldCollectionViewHeight) {
    self.messageCollectionView.contentOffset = CGPointMake(0, newCollectionViewHeight - oldCollectionViewHeight);
}

Для стола принцип такой же.

person Dmitry Malysh    schedule 27.12.2017

Вам не нужно ничего делать, пока вы находитесь в одном контроллере представления, ваше положение будет таким же. Боюсь, что где-то в вашем контроллере представления называется reloadData. Найдите метод, вызывающий scrollToRowAtIndexPath.

person aph340    schedule 10.10.2018
comment
Да, я разобрался. Решение было в принятом ответе. - person mylogon; 10.10.2018