Estoy tratando de desplazarse a la parte inferior de un UITableView después de que haya terminado de realizar [self.tableView reloadData]
.
Originalmente tenía
[self.tableView reloadData]
NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection: ([self.tableView numberOfSections]-1)];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Pero entonces leí que reloadData es asíncrono, por lo que el desplazamiento no se produce desde el self.tableView
, [self.tableView numberOfSections]
y [self.tableView numberOfRowsinSection
son todos 0.
Gracias.
Lo raro es que estoy usando:
[self.tableView reloadData];
NSLog(@"Number of Sections %d", [self.tableView numberOfSections]);
NSLog(@"Number of Rows %d", [self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1);
En la consola devuelve Secciones = 1, Fila = -1;
Cuando hago exactamente lo mismo en cellForRowAtIndexPath
obtengo Sections = 1 y Row = 8; (8 es correcto)
La recarga se produce durante la siguiente pasada de diseño, que normalmente ocurre cuando devuelves el control al bucle de ejecución (después de, digamos, que regrese tu acción de botón o lo que sea).
Así que una forma de ejecutar algo después de que la vista de tabla se recargue es simplemente forzar a la vista de tabla a realizar el diseño inmediatamente:
[self.tableView reloadData];
[self.tableView layoutIfNeeded];
NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection: ([self.tableView numberOfSections]-1)];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Otra forma es programar el código posterior al diseño para que se ejecute más tarde utilizando dispatch_async
:
[self.tableView reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection:([self.tableView numberOfSections]-1)];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
});
Investigando un poco más, he descubierto que la vista de tabla envía tableView:numberOfSections:
y tableView:numberOfRowsInSection:
a su fuente de datos antes de volver de reloadData
. Si el delegado implementa tableView:heightForRowAtIndexPath:
, la vista de tabla también envía eso (para cada fila) antes de volver de reloadData
.
Sin embargo, la vista tabla no envía tableView:cellForRowAtIndexPath:
o tableView:headerViewForSection
hasta la fase de diseño, que ocurre por defecto cuando devuelves el control al bucle de ejecución.
También encuentro que en un pequeño programa de prueba, el código de tu pregunta se desplaza correctamente a la parte inferior de la vista tabla, sin que yo haga nada especial (como enviar layoutIfNeeded
o usar dispatch_async
).
Swift:
extension UITableView {
func reloadData(completion: ()->()) {
UIView.animateWithDuration(0, animations: { self.reloadData() })
{ _ in completion() }
}
}
...somewhere later...
tableView.reloadData {
println("done")
}
Objetivo-C:
[UIView animateWithDuration:0 animations:^{
[myTableView reloadData];
} completion:^(BOOL finished) {
//Do something after that...
}];
Parece que la gente sigue leyendo esta pregunta y las respuestas. B/c de eso, I'm editar mi respuesta para eliminar la palabra Synchronous que es realmente irrelevante para esto.
Cuando [tableView reloadData]` vuelve, las estructuras de datos internas detrás de la tableView han sido actualizadas. Por lo tanto, cuando el método se completa se puede desplazar con seguridad a la parte inferior. He comprobado esto en mi propia aplicación. La respuesta ampliamente aceptada de @rob-mayoff, aunque también confusa en terminología, reconoce lo mismo en su última actualización.
Si tu tableView
no se desplaza hasta el fondo puede que tengas un problema en otro código que no has publicado. Tal vez usted está cambiando los datos después de desplazamiento es completa y usted 're no recargar y / o desplazamiento hasta el fondo entonces?
Añade algún registro como el siguiente para verificar que los datos de la tabla son correctos después de reloadData
. Tengo el siguiente código en una aplicación de ejemplo y funciona perfectamente.
// change the data source
NSLog(@"Before reload / sections = %d, last row = %d",
[self.tableView numberOfSections],
[self.tableView numberOfRowsInSection:[self.tableView numberOfSections]-1]);
[self.tableView reloadData];
NSLog(@"After reload / sections = %d, last row = %d",
[self.tableView numberOfSections],
[self.tableView numberOfRowsInSection:[self.tableView numberOfSections]-1]);
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[self.tableView numberOfRowsInSection:[self.tableView numberOfSections]-1]-1
inSection:[self.tableView numberOfSections] - 1]
atScrollPosition:UITableViewScrollPositionBottom
animated:YES];