web-dev-qa-db-fra.com

UITableView Refresh sans défilement

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?

14
ColdSteel

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.

10
user1190882

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)

27
David Seek

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];
20
Trung Phan

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
}
2
Marco M

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)
1
JhanviR

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.

0
Jack Chen

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)
    }
}
0
Yifan

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 

0
Apisteutos