iOS UItableview scrollToRowAtIndexPath 不再工作

问题描述 投票:0回答:10

今天早上我刚刚安装了新的 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 接收到正确的值,但没有执行滚动。

有什么想法吗?

objective-c uitableview ios6
10个回答
69
投票

目标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)
}

30
投票

对于最新版本的 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
.


4
投票

这适用于 iOS 12 和 13:

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

3
投票

我遇到了另一个关于 scrollToRowAtIndexPath 的问题(可能是一个错误),特别是在运行 ios11 的 iPhone X 上。我的桌子有几百个部分,在折叠模式下,大约 10 个部分适合可见屏幕。随着 indexPath 越来越深,滚动逐渐落后。

例如,当我希望搜索找到第 30 行中的项目时,ScrollPositionTop 将在我期望位于顶部的实际行之前多出一行。

当我测试搜索更深的行时,它开始落后更多,比如超过 100 行左右的深度,预期的行甚至没有进入可见区域。

到目前为止我发现的解决方法是对 dispatch_async 中的滚动说 animated:NO,然后它可以正常工作。


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)

2
投票

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];
}

2
投票

另一种可能的解决方法是在调用

layoutIfNeeded
之前先调用
scrollToRowAtIndexPath

[self.view layoutIfNeeded];
[self.tableView scrollToRowAtIndexPath...];

1
投票

它在 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];
}
});

0
投票

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)
}

0
投票

[self.tableView 开始更新]; ... [self.tableView 结束更新];

对我有用!

© www.soinside.com 2019 - 2024. All rights reserved.