web-dev-qa-db-ja.com

iOS UItableview scrollToRowAtIndexPathが機能しなくなった

今朝、iOS 6を含む新しいXcodeをインストールしました。

章と行を含むplistファイルがロードされたテーブルビューがあります。章でセクションを定義します。

ユーザーがチャプターとラインを選択すると、テーブルビューが自動的に正しい位置(viewDidLoad内)にスクロールされます。

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

これはiOS5シミュレータでうまく機能します。

IOS 6シミュレータでこれを試しても、スクロールは実行されません。エラーは発生しません。私はチェックしましたが、linePosとchapterPosは正しい値を受け取りますが、スクロールは実行されません。

なぜ何かアイデア?

19
HpTerm

iOSの最近のバージョンについては、Fyodor Volchyokの回答を読んでください。質問が最初に質問されたとき(2012年9月)、現在の答えは実用的なソリューションでした。最近のバージョンのiOSでも同じ問題が発生しましたが、現在Fyodor Volchyokの回答で解決されているので、その時点で彼の回答を+1する必要があります。


答えを見つけました。最初にテーブルビューでデータをリロードする必要があります

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

[self.tableView reloadData];

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

私は答えを見つけましたが、それがiOS6ではなくiOS5で機能している理由がわかりません。

[〜#〜]編集[〜#〜]

おそらく私はそれが機能していても最後の行を表示するのに問題があり、そのために質問を投稿したことを追加する必要があります

Itableview scrollToRowAtIndexPathが最後の行を正しく表示しない

@Rajもそれを要求したので、私はviewDidLoadでそれをトリガーしていたと言う必要があります。最後の行が正しく表示されないという問題を修正するには、viewDidAppearに配置する必要がありました。

27
HpTerm

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)
}
55
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
Aaron Scherbing

特にios11を実行しているiPhone XでscrollToRowAtIndexPathに関する別の問題(おそらくバグ)に遭遇しました。私のテーブルには数百のセクションがあり、折りたたみモードでは約10が表示画面に収まります。 indexPathが深くなるにつれて、スクロールは徐々に遅れました。

たとえば、検索で行30のアイテムを検索したい場合、ScrollPositionTopには、一番上にあると予想される実際の行の前に1行追加されます。

そして、より深い行の検索をテストしたところ、たとえば100行程度の深さを超えると、さらに遅れを取り始め、予想される行が可視領域にさえ入らなくなりました。

私がこれまでに見つけた回避策は、dispatch_async内でのスクロールに対してanimated:NOと言うことであり、グリッチなしで機能します。

2
Vasu Kargi

IOS7以降、UIViewControllerのデフォルトのプロパティautomaticallyAdjustsScrollViewInsetsYESです。これにより、ビューコントローラーがプッシュされたときに、システムがtableViewのcontentOffsetを調整します。あなたも[self.tableView scrollToRowAtIndexPath:rowIndexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];viewWillAppearにあります。 contentOffsetviewWillAppearの後にシステムによって変更されます。だから私の解決策は:

- (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];
}
1
SFeng

SwiftでのFyodor Volchyokの回答:

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
Tal Haham

それは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
wenjun

もう1つの可能な回避策は、layoutIfNeededを呼び出す前にscrollToRowAtIndexPathを呼び出すことです。

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