iphone - UITableView scrollToRowAtIndexPath se desplaza al desplazamiento incorrecto con estimadaRowHeight en iOS 7
ios7 (7)
Estoy utilizando el método estimatedRowHeight
de UITableView en iOS 7, que funciona perfectamente para cargar rápidamente un UITableView con 5000 filas de alturas variables.
Mi UITableView consta de 50 secciones. Cada sección tiene 100 filas, de altura variable. Al principio, utilizo estimatedRowHeight
para una carga rápida, pero después de eso, cuando llamo scrollToRowAtIndexPath
, mi UITableView se desplaza al desplazamiento incorrecto . Puedo entender por qué esto es así, porque tiene un valor estimatedRowHeight
heightForRowAtIndexPath
hasta que me desplazo por toda la tabla y las alturas de celda adecuadas se establecen en el método de delegado heightForRowAtIndexPath
.
¿Alguna solución?
Cuando se llama a scrollToRowAtIndexPath
, la altura de todas las celdas b / w de la posición actual y el desplazamiento objetivo no se calculan. Solo algunos de ellos son.
En su lugar, UITableView utiliza estimatedRowHeight
para calcular el desplazamiento del objetivo que conduce a un desplazamiento incorrecto.
Me enfrento al mismo problema y encontré un pequeño truco (que realmente no me gusta) para calcular la altura exacta de la celda solo una vez después de los relaodData
iniciales de relaodData
. He insertado dos líneas a continuación:
tableView.reloadData()
// only for the initial reloadData
let numSections = tableView.numberOfSections
let numRowsInLastSection = tableView.numberOfRowsInSection(numSections-1)
// scrolls to the last row in the tableView
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: numRows-1, inSection: numSections-1), atScrollPosition: .Bottom, animated: false)
// back again to the original position(which is 0 for this is only called right after the initial reloadData)
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: .Top, animated: false)
Esto hace que la vista de tabla aparezca en la pantalla tarde, pero creo que es aceptable en lugar de congelar la interfaz de usuario después de que aparezca la vista de tabla. Es incluso mejor cuando se llama a una API al principio porque se siente como un pequeño retraso en la red, no en el retraso de la interfaz de usuario.
Después de esto, tableView salta a la posición exacta de las celdas.
Sí, a mi tampoco me gusta esta solución: |
EDITAR:
La única razón por la que hice esto fue para calcular la altura real de la fila llamando a cellForRowAtIndexPath:
pero descubrí que al dar la altura estimada adecuada para cada fila por el método delegado estimatedHeightForRowAtIndexPath:
lugar de dar un valor estático a UITableView.estimatedRowHeight
resuelve el problema.
Lo que finalmente hice fue willDisplayCell:forRowAtIndexPath:
en caché las alturas de las filas de willDisplayCell:forRowAtIndexPath:
al disco y usar ese valor en estimatedHeightForRowAtIndexPath:
Al hacer esto, estimatedHeightForRowAtIndexPath:
para todas las filas se llama al principio y scrollToRowAtIndexPath
funciona bien.
Desafortunadamente, este problema es de esperar cuando se utiliza el valor estimatedRowHeight
de estimatedRowHeight
en su código con un valor tan bajo . Cuando scrollToRowAtIndexPath
a scrollToRowAtIndexPath
, no calcula activamente el tamaño correcto a medida que avanza. La causa subyacente es que, si se desplazó de la Sección 1 a la Sección 2, es posible que pueda calcular la posición correcta sobre la marcha y la estimatedRowHeight
de las celdas si fuera un dispositivo relativamente nuevo. Cualquier dispositivo antiguo se pondría de rodillas, e incluso cualquier otro nuevo sería así si tuviera que procesar 5000 celdas, por ejemplo.
Una posible solución a su problema podría ser aumentar la constante estimatedRowHeight
RowHeight para que el dispositivo no tenga que hacer tanto trabajo.
La solución para mí fue establecer el valor estimatedRowHeight to 0
No es la solución más bonita, pero utilizo una solución alternativa para este problema que hace el truco. Siempre actualice el valor estimado de RowHeight a la celda computada más alta y luego use algo como esto:
- Desplácese por el contenido de tableView para compensar cero.
Termine llamando a scrollToRowAtIndexPath para indexar la ruta cero.
[self.tableView setContentOffset:CGPointZero animated:YES]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES]; });
Como resultado, el tableView debería desplazarse hacia la parte superior con bastante suavidad.
Parece funcionar después de que la vista fue diseñada por el sistema. Estoy llamando a scrollToRowAtIndexPath con los resultados correctos en viewDidAppear del VC. Lo que no es muy bonito, por supuesto, porque se desplaza cuando la vista ya está visible ...
Todavía no hay una solución sólida, pero para mí fue aceptable realizar un desplazamiento sin animación que funcionó bien en el sentido de que se desplaza a la celda esperada con el desplazamiento correcto, a pesar de lo que se menciona en openradar.me/20829131 .
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition:.Top, animated: false)
intente agregar este código en -cellForRowAtIndexPath: justo antes de devolver la celda
[cell layoutIfNeeded]