ios uitableview reloaddata contentoffset

ios - Cómo mantener UIT-OutView contentoffset después de llamar a-reloadData



uitableview (12)

Swift 4 variante de @Skywalker respuesta:

fileprivate var heightDictionary: [Int : CGFloat] = [:] override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { heightDictionary[indexPath.row] = cell.frame.size.height } override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { let height = heightDictionary[indexPath.row] return height ?? UITableViewAutomaticDimension }

Otra solución (extraída de MessageKit):

Este método debe llamarse en lugar de reloadData . Esto puede adaptarse a casos específicos.

public func reloadDataAndKeepOffset() { // stop scrolling setContentOffset(contentOffset, animated: false) // calculate the offset and reloadData let beforeContentSize = contentSize reloadData() layoutIfNeeded() let afterContentSize = contentSize // reset the contentOffset after data is updated let newOffset = CGPoint( x: contentOffset.x + (afterContentSize.width - beforeContentSize.width), y: contentOffset.y + (afterContentSize.height - beforeContentSize.height)) setContentOffset(newOffset, animated: false) }

CGPoint offset = [_table contentOffset]; [_table reloadData]; [_table setContentOffset:offset animated:NO]; //unuseful // __block UITableView *tableBlock = _table; // [self performBlock:^(id sender) { // [tableBlock setContentOffset:offset]; // } afterDelay:2];

No conozco ningún método delegado que se llame después de reloadData . Y afterDelay:2 puede ser demasiado corto o demasiado largo, entonces ¿cómo puedo implementarlo?

Mi inglés no es bueno, espero que puedas entender ...


En mi caso, desmarque la altura de fila automática y calcule el problema automático resuelto


Estaba teniendo problemas con esto porque me meto con el tamaño de la celda en mi método cellForRowAtIndexPath. Noté que la información del tamaño estaba desactivada después de hacer ReloadData, así que me di cuenta de que necesitaba forzarlo a la distribución inmediatamente antes de volver a configurar el offset de contenido.

CGPoint offset = tableView.contentOffset; [tableView.messageTable reloadData]; [tableView layoutIfNeeded]; // Force layout so things are updated before resetting the contentOffset. [tableView setContentOffset:offset];


Esto está funcionando al 100%

change the tableView.reloadData()

dentro

tableView.reloadRows(at: tableView!.indexPathsForVisibleRows!, with: .none)


Hace poco estuve trabajando con reloadData - reloadData no cambia el contentOffset ni desplaza la vista de tabla. En realidad, permanece igual si el desplazamiento es menor que la nueva cantidad de datos.


La respuesta de @ Skywalker mostró la mejor solución para el problema de la altura estimada de las celdas. Pero a veces el problema está en otro lugar.
A veces, el problema depende del contenidoInsectos de la vista de tabla. Si realiza una recarga de datos mientras TableView no está visible en la pantalla, puede enfrentar una compensación incorrecta después de que aparezca la vista de tabla en la pantalla.
Sucede porque UIViewController puede controlar las inserciones si su scrollView cuando aparece la vista de desplazamiento para permitir la mentira de scrollView debajo de la barra de navegación y la barra de estado transparentes.
Me he enfrentado a este comportamiento en iOS 9.1


Llamar a reloadData en tableView no cambia el offset del contenido. Sin embargo, si está utilizando UITableViewAutomaticDimension que se introdujo en iOS 8, podría tener un problema.

Al usar UITableViewAutomaticDimension , es necesario escribir el método delegado tableView: estimatedHeightForRowAtIndexPath: y devolver UITableViewAutomaticDimension junto con tableView: heightForRowAtIndexPath: que también devuelve lo mismo.

Para mí, tuve problemas en iOS 8 mientras usaba esto. Fue porque el método UITableViewAutomaticDimension estimatedHeightForRowAtIndexPath: método devolvía valores inexactos a pesar de que estaba usando UITableViewAutomaticDimension . Fue un problema con iOS 8 ya que no había problemas con los dispositivos con iOS 9.

Resolví este problema usando un diccionario para almacenar el valor de la altura de la celda y devolverla. Esto es lo que hice.

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { NSNumber *key = @(indexPath.row); NSNumber *height = @(cell.frame.size.height); [self.cellHeightsDictionary setObject:height forKey:key]; } - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { NSNumber *key = @(indexPath.row); NSNumber *height = [self.cellHeightsDictionary objectForKey:key]; if (height) { return height.doubleValue; } return UITableViewAutomaticDimension; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return UITableViewAutomaticDimension; }

El control de si existe altura es la primera vez que se carga la página.


Por defecto, reloadData mantiene el contentOffset. Sin embargo, podría actualizarse si tiene valores estimados incorrectos de RowHeight.


Porque funciona bien

[tView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];


Si implementa el método estimatedHeightForRowAtIndexPath y su estimación no es correcta, es posible que se encuentre en esta situación.

Para resolver esto, puede devolver una altura grande que sea más grande que la altura de cada celda en su tableView, así:

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { return 800.f; // if 800 is bigger than every possible value of your cell height. }


Si inserta datos al principio de su matriz dataSource, debe cambiar contentOffset siguiente manera: Swift 3+

func prepareReloadData() { let previousContentHeight = tableView.contentSize.height let previousContentOffset = tableView.contentOffset.y tableView.reloadData() let currentContentOffset = tableView.contentSize.height - previousContentHeight + previousContentOffset tableView.contentOffset = CGPoint(x: 0, y: currentContentOffset) }


Tuve el mismo problema, pero ninguna de las respuestas sugeridas aquí funcionó. Así es como lo resolví. Subclass UITableView y anula el método de layoutSubviews como este:

override func layoutSubviews() { let offset = contentOffset super.layoutSubviews() contentOffset = offset }