iOS UItableview scrollToRowAtIndexPath not working

2019-02-05 23:29发布

This morning I just installed new Xcode which includes iOS 6.

I have a table view loaded with a plist file containing chapters and lines. Chapters define the sections.

The user selects chapter and line and the tableview is automatically scrolled to the correct position (in the viewDidLoad).

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:linePos inSection:chapterPos];
[self.tableView scrollToRowAtIndexPath:indexPath 
    atScrollPosition:UITableViewScrollPositionTop animated:YES];

this works just great in iOS5 simulator.

Trying this in the iOS 6 simulator the scroll is not performed. I get no errors. I have checked, linePos and chapterPos receive correct values but the scroll is not performed.

Any ideas why ?

7条回答
祖国的老花朵
2楼-- · 2019-02-05 23:57

For recent versions of iOS, please read Fyodor Volchyok's answer. Note that it's not marked as the accepted answer simply because at the time the question was first asked (Sept. 2012), the current answer was the working solution. More recent versions of iOS also got the same problem which is now solved by Fyodor Volchyok's answer, so you should +1 his answer at that moment.


I found the answer. I have to first reload the data in the tableview

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:linePos inSection:chapterPos];

[self.tableView reloadData];

[self.tableView scrollToRowAtIndexPath:indexPath 
    atScrollPosition:UITableViewScrollPositionTop animated:YES];

Even though I found the answer I don't know why it is working in iOS5 and not in iOS6.

EDIT

Perhaps I should add that even though it was working, I was still having a problem in displaying the last row and posted a question for that

UItableview scrollToRowAtIndexPath not displaying last row correctly

As @Raj also asked for it, I should say that I was triggering that in the viewDidLoad. To correct the problem of the last row not displaying correctly I had to put it in the viewDidAppear.

查看更多
老娘就宠你
3楼-- · 2019-02-05 23:58

I ran into another issue (probably a bug) with scrollToRowAtIndexPath specifically on an iPhone X running ios11. My table has a few hundred sections and in collapsed mode ~10 would fit in the visible screen. As the indexPath got deeper, the scrolling gradually fell behind.

For example, when I wanted the search to find the item in row 30, the ScrollPositionTop would have one additional row before the actual row I expect to be at the top.

And as I tested searching for deeper rows, it started falling behind even more where for say anything past 100 rows deep or so, the expected row did not even come in the visible area.

The workaround I found so far is to say animated:NO for the scrolling within dispatch_async, then it works without any glitches.

查看更多
【Aperson】
4楼-- · 2019-02-06 00:00

It worked for me in 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];
}
});
查看更多
爷、活的狠高调
5楼-- · 2019-02-06 00:07

I'm adding this answer as an addition to Fyodor Volchyok's answer. I also found that dispatching solves the issue. I was able to find a workaround that doesn't dispatch.

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)
查看更多
劫难
6楼-- · 2019-02-06 00:09

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)
}
查看更多
欢心
7楼-- · 2019-02-06 00:13

After iOS7 the property automaticallyAdjustsScrollViewInsets of UIViewController default is YES. It will cause system to adjust the contentOffset of tableView when the view controller pushed. Even you call [self.tableView scrollToRowAtIndexPath:rowIndexPath atScrollPosition:UITableViewScrollPositionNone animated:NO]; in the viewWillAppear. The contentOffset also will be changed by system after viewWillAppear. So my solution is:

- (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];
}
查看更多
登录 后发表回答