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 прокрутка не выполняется. Я не получаю ошибок. Я проверил, строкиПос и главаПос получают правильные значения, но прокрутка не выполняется.

Любые идеи, почему?


person HpTerm    schedule 20.09.2012    source источник
comment
просто чтобы добавить к боли и страданиям, он снова сломался 5 лет спустя в iOS 11.   -  person Sam B    schedule 27.09.2017


Ответы (9)


Цель-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];
});

Быстрый

tableView.reloadData()
DispatchQueue.main.async {
    let indexPath = IndexPath(row: linePos, section: chapterPos)
    self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
person Fyodor Volchyok    schedule 12.12.2014
comment
Это важное исправление, без которого приложение могло бы случайно вылететь, в зависимости от процессов reloadData. - person BootMaker; 26.10.2015
comment
это единственное, что работает для меня (iOS 9.1). scrollToRowAtIndexPath всегда не удавалось прокрутить до самой нижней ячейки, если я не обернул ее в dispatch_async(dispatch_get_main_queue(), { ... }, хотя scrollToRowAtIndexPath уже вызывался из основного потока. - person kas-kad; 07.12.2015
comment
Вероятно, это правильный ответ, ПЛЮС поместите это в viewDidAppear: - person Brooks Hanes; 22.12.2015
comment
У меня это сработало в viewWillAppear и без предварительной перезагрузки таблицы. Спасибо! - person Tuslareb; 17.03.2016
comment
Просто удивительно! Я потерял почти день с этой проблемой. Спасибо, что поделились! - person Thomás Pereira; 02.02.2018
comment
Больше не работает. Я вызываю версию objc-C в своем didSelectRowAtIndexPath, но не прокручиваю :( - person Hyder; 08.09.2018

По последним версиям iOS прочитайте ответ Федора Волчёка. Обратите внимание, что он не помечен как принятый ответ просто потому, что на момент первого вопроса (сентябрь 2012 г.) текущий ответ был рабочим. решение. Более поздние версии iOS также столкнулись с той же проблемой, которая теперь решается ответом Федора Волчёка, поэтому вы должны +1 к его ответу в этот момент.


Я нашел ответ. Мне нужно сначала перезагрузить данные в табличном представлении

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.

person HpTerm    schedule 21.09.2012
comment
Спасибо за эту информацию, я только что столкнулся с тем же. Я также заметил, что он не анимирует прокрутку таблицы, а просто отображает ее в выбранной строке. - person John T; 23.09.2012
comment
Вы запускаете вызов scrollToRowAtIndexPath в своем методе -viewDidLoad? - person Raj Pawan Gumdal; 16.10.2012

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

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)
person Aaron Scherbing    schedule 05.01.2016
comment
У меня была проблема с многопоточностью: когда я использую диспетчеризацию, один из моих методов начинает вызываться дважды. И теперь это работает как по волшебству!!! :-) - person Vitya Shurapov; 11.04.2017

Это работает в iOS 12 и 13:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { 
    self.tableView.scrollToRow(at: IndexPath(row: 0, section: 1), at: .bottom, animated: true) 
}
person Jovan Ivanov    schedule 17.01.2020

Я столкнулся с другой проблемой (вероятно, ошибкой) с scrollToRowAtIndexPath, особенно на iPhone X под управлением ios11. В моей таблице несколько сотен разделов, и в свернутом режиме на видимом экране поместилось бы около 10 разделов. По мере того, как indexPath становился глубже, прокрутка постепенно отставала.

Например, когда я хотел, чтобы поиск находил элемент в строке 30, ScrollPositionTop имел бы одну дополнительную строку перед фактической строкой, которая, как я ожидаю, будет наверху.

И когда я тестировал поиск более глубоких строк, он начал отставать еще больше, когда, скажем, что-то более 100 строк в глубину или около того, ожидаемая строка даже не попала в видимую область.

Обходной путь, который я нашел до сих пор, заключается в том, чтобы сказать анимированный: НЕТ для прокрутки в dispatch_async, тогда он работает без каких-либо сбоев.

person Vasu Kargi    schedule 28.11.2017

После 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];
}
person SFeng    schedule 17.12.2015

Еще один возможный обходной путь — вызвать layoutIfNeeded перед вызовом scrollToRowAtIndexPath.

[self.view layoutIfNeeded];
[self.tableView scrollToRowAtIndexPath...];
person Tikhonov Alexander    schedule 10.07.2019

Ответ Федора Волчёка на Swift:

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)
}
person Tal Haham    schedule 23.10.2016

У меня сработало на 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];
}
});
person wenjun    schedule 12.10.2017