IOS UItableview scrollToRowAtIndexPath больше не работает
Сегодня утром я только что установил новый Xcode, который включает iOS 6.
У меня есть табличный вид, загруженный с plist файлом, содержащим главы и строки. Главы определяют разделы.
Пользователь выбирает главу и строку, и представление таблицы автоматически прокручивается в нужное положение (в viewDidLoad).
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:linePos inSection:chapterPos];
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop animated:YES];
это отлично работает в симуляторе iOS5.
Пробовав это в симуляторе iOS 6, прокрутка не выполняется. У меня нет ошибок. Я проверил, linePos и chapterPos получают правильные значения, но прокрутка не выполняется.
Любые идеи, почему?
Ответы
Ответ 1
Для последних версий iOS, пожалуйста, прочитайте ответ Fyodor Volchyok. Обратите внимание, что это не отмечено как принятый ответ просто потому, что в то время, когда вопрос был впервые задан (сентябрь 2012 г.), текущий ответ было рабочим решением.
Более свежие версии iOS также получили ту же проблему, которая теперь решена в ответ Федором Волчиком, поэтому в этот момент вы должны ответить +1.
Я нашел ответ. Я должен сначала перезагрузить данные в tableview
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:linePos inSection:chapterPos];
[self.tableView reloadData];
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop animated:YES];
Даже если я нашел ответ, я не знаю, почему он работает в iOS5, а не в iOS6.
ИЗМЕНИТЬ
Возможно, я должен добавить, что даже несмотря на то, что он работал, у меня все еще была проблема с отображением последней строки и отправил вопрос для этого
UItableview scrollToRowAtIndexPath не отображает последнюю строку правильно
Поскольку @Raj также попросил об этом, я должен сказать, что я запускал это в viewDidLoad
. Чтобы исправить проблему последней строки, не отображаемой правильно, мне пришлось поместить ее в viewDidAppear
.
Ответ 2
Objective-C
[self.tableView reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
NSIndexPath *rowIndexPath = [NSIndexPath indexPathForRow:3 inSection:0];
[self.tableView scrollToRowAtIndexPath:rowIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
});
Swift
tableView.reloadData()
DispatchQueue.main.async {
let indexPath = IndexPath(row: linePos, section: chapterPos)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
Ответ 3
Я добавляю этот ответ в качестве дополнения к Fyodor Volchyok. Я также обнаружил, что диспетчер решает проблему. Я смог найти обходное решение, которое не отправляет.
self.tableView.reloadData()
let index = // the desired index path
// For some reason, requesting the cell prior to
// scrolling was enough to workaround the issue.
self.tableView.cellForRowAtIndexPath(index)
self.tableView.scrollToRowAtIndexPath(index, atScrollPosition: .Top, animated: false)
Ответ 4
Я столкнулся с другой проблемой (вероятно, с ошибкой) с scrollToRowAtIndexPath специально для iPhone X с ios11. Моя таблица имеет несколько сотен секций, а в режиме с обрушением ~ 10 будет помещаться на видимом экране. По мере того, как indexPath становился все глубже, прокрутка постепенно отставала.
Например, когда я хотел, чтобы поиск нашел элемент в строке 30, ScrollPositionTop имел бы одну дополнительную строку до того, как фактическая строка я ожидаю быть наверху.
И когда я тестировал поиск более глубоких строк, он начал падать еще больше, где, скажем, что-либо за 100 строк в глубину или около того, ожидаемая строка даже не попадала в видимую область.
Обходной путь, который я нашел до сих пор, это сказать анимированный: НЕТ для прокрутки в dispatch_async, тогда он работает без каких-либо сбоев.
Ответ 5
После iOS7 свойство automaticallyAdjustsScrollViewInsets
UIViewController по умолчанию - YES
. Это приведет к тому, что система будет настраивать contentOffset
tableView при нажатии контроллера представления. Даже вы вызываете [self.tableView scrollToRowAtIndexPath:rowIndexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];
в viewWillAppear
. contentOffset
также будет изменен системой после viewWillAppear
. Итак, мое решение:
- (void)viewDidLoad {
[super viewDidLoad];
self.automaticallyAdjustsScrollViewInsets = NO;
/// any other codes
}
- (void)viewWillLayoutSubviews {
self.tableView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length, 0, 0, 0);
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// change tableView data source
[self.tableView reloadData];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self.dataSourceArray count] - 1 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];
}
Ответ 6
Фёдор Волчик отвечает в Свифте:
tableView.reloadData()
let indexPath = NSIndexPath(forRow: linePos, inSection: chapterPos)
// make sure the scroll is done after data reload was finished
dispatch_async(dispatch_get_main_queue()) {
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
}
Ответ 7
Это сработало для меня в ios11
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0
dispatch_async(dispatch_get_main_queue(), ^{
NSInteger numberOfSections = self.tableView.numberOfSections;
if (numberOfSections > 0)
{
NSInteger lastSection = numberOfSections - 1;
NSInteger lastRowInLastSections = [self.tableView numberOfRowsInSection:lastSection] - 1;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:lastRowInLastSections inSection:lastSection];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:isAnimated];
}
});
Ответ 8
Еще один возможный обходной путь - вызвать layoutIfNeeded
перед вызовом scrollToRowAtIndexPath
.
[self.view layoutIfNeeded];
[self.tableView scrollToRowAtIndexPath...];