J'ai un _TableView
avec des éléments, et je veux définir l'actualisation automatique, et je ne veux pas le faire défiler lors de l'actualisation, disons que l'utilisateur a fait défiler 2 pages vers le bas et l'actualisation a été modifiée -> je souhaite donc mettre le contenu actualisé à le haut de la table sans interrompre le défilement de l'utilisateur
Supposons que l’utilisateur se trouve à la ligne 18 Et que le _dataSource
est actualisé afin d’obtenir 4 éléments, je souhaite donc que l’utilisateur reste sur l’article qu’il était.
Quelle serait la meilleure approche pour y arriver?
Je montre si une seule ligne est ajoutée. Vous pouvez l'étendre à plusieurs lignes.
// dataArray is your data Source object
[dataArray insertObject:name atIndex:0];
CGPoint contentOffset = self.tableView.contentOffset;
contentOffset.y += [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
[self.tableView reloadData];
[self.tableView setContentOffset:contentOffset];
Mais pour que cela fonctionne, vous devez avoir défini la méthode - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
. Sinon, vous pouvez directement attribuer à votre table une hauteur de rangée si elle est constante.
Pour Swift 3+ :
Vous devez enregistrer le décalage actuel de la UITableView
, puis le recharger, puis le rétablir sur la UITableView
.
J'ai créé cette fonction à cette fin:
func reload(tableView: UITableView) {
let contentOffset = tableView.contentOffset
tableView.reloadData()
tableView.layoutIfNeeded()
tableView.setContentOffset(contentOffset, animated: false)
}
Appelez-le simplement avec: reload(tableView: self.tableView)
Swift 3
let contentOffset = self.tableView.contentOffset
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.setContentOffset(contentOffset, animated: false)
Ceci est une erreur de iOS8 lors de l'utilisation de UITableViewAutomatic Dimension. Nous avons besoin de stocker le contenu du tableau, de recharger le tableau, de forcer la disposition et de définir contenOffset.
CGPoint contentOffset = self.tableView.contentOffset;
[self.tableView reloadData];
[self.tableView layoutIfNeeded];
[self.tableView setContentOffset:contentOffset];
Je le fais de cette façon:
messages.insertContentsOf(incomingMsgs.reverse(), at: 0)
table.reloadData()
// This is for the first load, first 20 messages, scroll to bottom
if (messages.count <= 20) {
let indexToScroll = NSIndexPath(forRow: saferSelf.messages.count - 1, inSection: 0)
table.scrollToRowAtIndexPath(indexToScroll, atScrollPosition: .Top , animated: false)
}
// This is to reload older messages on top of tableview
else {
let indexToScroll = NSIndexPath(forRow: incomingMsgs.count, inSection: 0)
table.scrollToRowAtIndexPath(indexToScroll, atScrollPosition: .Top , animated: false)
// Remove the refreshControl.height + tableHeader.height from the offset so the content remain where it was before reload
let theRightOffset = CGPointMake(0, table.contentOffset.y - refreshControl.frame.height - table.headeView.frame.height)
table.setContentOffset(theRightOffset, animated: false)
}
... aussi, puisque j'utilise la hauteur de cellule dynamique, pour éviter certaines bizarreries, l'estimation est mise en cache:
var heightAtIndexPath = [NSIndexPath: CGFloat]()
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return heightAtIndexPath[indexPath] ?? UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
heightAtIndexPath[indexPath] = cell.frame.height
}
Ce code empêchera les animations inutiles et maintiendra le décalage du contenu de la vue de défilement. Cela a bien fonctionné pour moi.
let lastScrollOffset = tableView.contentOffset
tableView.beginUpdates()
tableView.reloadData()
tableView.endUpdates()
tableView.layer.removeAllAnimations()
tableView.setContentOffset(lastScrollOffset, animated: false)
essayer de remplacer
reloadData
avec
tableView.reloadRows
(at: tableView!.indexPathsForVisibleRows!, with: .none
),
mais vous devriez faire attention à no cells
, si no cells
, cette méthode devrait causer un crash.
Utiliser l'extension
créez UITableViewExtensions.Swift
et ajoutez ce qui suit:
extension UITableView {
func reloadDataWithoutScroll() {
let offset = contentOffset
reloadData()
layoutIfNeeded()
setContentOffset(offset, animated: false)
}
}
Lorsque vous voulez recharger, vous devez
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
et aussi utiliser cette UITableViewDelegate
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 'your maximum cell's height'
}
et votre tableView restera sur la position de défilement précédente sans défilement