今朝、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は正しい値を受け取りますが、スクロールは実行されません。
なぜ何かアイデア?
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
に配置する必要がありました。
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)
}
私はこの答えをフョードル・ボルチョクの答えに加えて追加します。また、派遣することで問題が解決することもわかりました。ディスパッチしない回避策を見つけることができました。
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)
特にios11を実行しているiPhone XでscrollToRowAtIndexPathに関する別の問題(おそらくバグ)に遭遇しました。私のテーブルには数百のセクションがあり、折りたたみモードでは約10が表示画面に収まります。 indexPathが深くなるにつれて、スクロールは徐々に遅れました。
たとえば、検索で行30のアイテムを検索したい場合、ScrollPositionTopには、一番上にあると予想される実際の行の前に1行追加されます。
そして、より深い行の検索をテストしたところ、たとえば100行程度の深さを超えると、さらに遅れを取り始め、予想される行が可視領域にさえ入らなくなりました。
私がこれまでに見つけた回避策は、dispatch_async内でのスクロールに対してanimated:NOと言うことであり、グリッチなしで機能します。
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];
}
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)
}
それは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];
}
});
もう1つの可能な回避策は、layoutIfNeeded
を呼び出す前にscrollToRowAtIndexPath
を呼び出すことです。
[self.view layoutIfNeeded];
[self.tableView scrollToRowAtIndexPath...];