今天早上我刚刚安装了新的 Xcode,其中包括 iOS 6.
我有一个表视图加载了一个包含章节和行的 plist 文件。章节定义了部分。
用户选择章节和行,tableview 自动滚动到正确的位置(在 viewDidLoad 中)。
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:linePos inSection:chapterPos];
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop animated:YES];
这在 iOS5 模拟器中工作得很好。
在 iOS 6 模拟器中尝试此操作不会执行滚动。我没有错误。我已经检查过,linePos 和 chapterPos 接收到正确的值,但没有执行滚动。
有什么想法吗?
目标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)
}
对于最新版本的 iOS,请阅读 Fyodor Volchyok 的回答。 请注意,它没有被标记为已接受的答案,因为在首次提出问题时(2012 年 9 月),当前答案是有效的解决方案。 较新版本的 iOS 也遇到了同样的问题,现在由 Fyodor Volchyok 的回答解决了,所以你应该在那一刻 +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
.
这适用于 iOS 12 和 13:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.tableView.scrollToRow(at: IndexPath(row: 0, section: 1), at: .bottom, animated: true)
}
我遇到了另一个关于 scrollToRowAtIndexPath 的问题(可能是一个错误),特别是在运行 ios11 的 iPhone X 上。我的桌子有几百个部分,在折叠模式下,大约 10 个部分适合可见屏幕。随着 indexPath 越来越深,滚动逐渐落后。
例如,当我希望搜索找到第 30 行中的项目时,ScrollPositionTop 将在我期望位于顶部的实际行之前多出一行。
当我测试搜索更深的行时,它开始落后更多,比如超过 100 行左右的深度,预期的行甚至没有进入可见区域。
到目前为止我发现的解决方法是对 dispatch_async 中的滚动说 animated:NO,然后它可以正常工作。
我将此答案添加为 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)
iOS7之后UIViewController的属性
automaticallyAdjustsScrollViewInsets
默认为YES
。它会导致系统在视图控制器推送时调整 tableView 的contentOffset
。即使你在[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];
}
另一种可能的解决方法是在调用
layoutIfNeeded
之前先调用scrollToRowAtIndexPath
。
[self.view layoutIfNeeded];
[self.tableView scrollToRowAtIndexPath...];
它在 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];
}
});
Fyodor Volchyok 在 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)
}
[self.tableView 开始更新]; ... [self.tableView 结束更新];
对我有用!