Ce matin, je viens d'installer le nouveau Xcode, qui inclut iOS 6.
J'ai une vue de table chargée avec un fichier plist contenant des chapitres et des lignes. Les chapitres définissent les sections.
L'utilisateur sélectionne le chapitre et la ligne et la vue de table défile automatiquement jusqu'à la position correcte (dans le viewDidLoad).
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:linePos inSection:chapterPos];
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop animated:YES];
cela fonctionne très bien dans le simulateur iOS5.
Si vous essayez ceci dans le simulateur iOS 6, le défilement n'est pas effectué. Je ne reçois aucune erreur. J'ai vérifié, linePos et chapterPos reçoivent les valeurs correctes mais le défilement n'est pas effectué.
Des idées pourquoi?
Pour les versions récentes d'iOS, veuillez lire la réponse de Fyodor Volchyok. Notez que ce n'est pas indiqué comme la réponse acceptée simplement parce qu'au moment où la question a été posée (septembre 2012), la réponse actuelle était la solution opérationnelle. problème qui est maintenant résolu par la réponse de Fyodor Volchyok, vous devriez donc +1 sa réponse à ce moment-là.
J'ai trouvé la réponse. Je dois d'abord recharger les données dans la table
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:linePos inSection:chapterPos];
[self.tableView reloadData];
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop animated:YES];
Même si j'ai trouvé la réponse, je ne sais pas pourquoi cela fonctionne dans iOS5 et non dans iOS6.
EDIT
Je devrais peut-être ajouter que même si cela fonctionnait, j'avais toujours du mal à afficher la dernière ligne et à poser une question à ce sujet.
UItableview scrollToRowAtIndexPath n'affichant pas la dernière ligne correctement
Comme @Raj l'a également demandé, je dois dire que c'est ce que j'ai déclenché dans la viewDidLoad
. Pour corriger le problème de la dernière ligne ne s’affichant pas correctement, je devais le mettre dans la variable viewDidAppear
.
Objectif 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];
});
Rapide
tableView.reloadData()
DispatchQueue.main.async {
let indexPath = IndexPath(row: linePos, section: chapterPos)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
J'ai rencontré un autre problème (probablement un bug) avec scrollToRowAtIndexPath spécifiquement sur un iPhone X exécutant ios11. Ma table a quelques centaines de sections et en mode réduit, environ 10 correspond à l’écran visible. Au fur et à mesure que le chemin indexPath devenait plus profond, le défilement a pris du retard.
Par exemple, lorsque je souhaitais que la recherche trouve l'élément de la ligne 30, l'objet ScrollPositionTop aurait une ligne supplémentaire avant la ligne réelle que je pense être en haut.
Et alors que j’essayais de chercher des rangées plus profondes, cela a commencé à prendre encore plus de place, disons que la profondeur attendue n’était même pas visible dans la zone visible.
La solution de contournement que j'ai trouvée jusqu'ici consiste à dire animé: NON pour le défilement dans dispatch_async, alors cela fonctionne sans aucun problème.
J'ajoute cette réponse à la réponse de Fyodor Volchyok. J'ai aussi constaté que le dispatching résout le problème. J'ai pu trouver une solution de contournement qui ne soit pas expédiée.
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)
Après iOS7, la propriété automaticallyAdjustsScrollViewInsets
de la valeur par défaut UIViewController est YES
. Le système ajustera la contentOffset
de tableView lorsque le contrôleur de vue sera poussé. Même si vous appelez [self.tableView scrollToRowAtIndexPath:rowIndexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];
dans la viewWillAppear
. La contentOffset
sera également modifiée par le système après viewWillAppear
. Donc ma solution est:
- (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];
}
La réponse de Fyodor Volchyok dans 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)
}
Cela a fonctionné pour moi dans 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];
}
});