web-dev-qa-db-fra.com

UITableView rebondit en haut d'une section lors de l'appel de reloadRowsAtIndexPaths

Lorsqu'un utilisateur appuie sur un bouton de l'une de mes lignes, je mets à jour le modèle sous-jacent pour cette ligne, puis j'appelle reloadRowsAtIndexPaths pour la ligne donnée (c'est-à-dire un rechargement d'une seule ligne).

- (IBAction)handleCompleteTouchEvent:(UIButton *)sender {
    NSIndexPath *indexPath = [self.tableView indexPathForView:sender];
    id item = [self dataForIndexPath:indexPath];

    if ([item respondsToSelector:@selector(completed)]) {
        // toogle completed value
        BOOL completed = ![[item valueForKey:@"completed"] boolValue];
        [item setValue:[NSNumber numberWithBool:completed] forKey:@"completed"];

        [self.tableView beginUpdates];
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        [self.tableView endUpdates];
    }
}

Le problème est que la vue de table rebondit vers le haut de la section après avoir passé cet appel. Comment puis-je empêcher que cela se produise et conserver la position du défilement là où elle se trouve?

35
xsee

Ah ah! J'ai trouvé le problème et je vais répondre à ma propre question pour la pauvre âme qui se heurtera à ce problème à l'avenir.

Toutes mes cellules ont une hauteur variable, donc j'utilisais la nouvelle méthode iOS7 dans UITableViewDelegate en pensant que cela pouvait accélérer le temps de rendu (même si j'en avais vraiment besoin):

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;

Quoi qu'il en soit, la mise en œuvre de cette méthode a pour effet pervers de faire rebondir la table en haut de la section lorsqu'elle appelle:

[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

Pour résoudre le problème du rebond, je viens de supprimer le remplacement de cette méthode estiméeHeightForRowAtIndexPath et maintenant tout fonctionne comme il se doit. Heureux enfin.

47
xsee

Vous devriez pouvoir faire ce que vous essayez de faire en modifiant directement le contenu de la cellule. Par exemple, si vous utilisez la classe de base UITableViewCell et que les données de votre modèle correspondent à un NSString que vous affichez dans la cellule de la vue tableau, vous pouvez procéder comme suit (après avoir modifié votre modèle de données) au lieu d'appeler reloadRowsAtIndexPaths:

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *label = [cell textLabel];
label.text = @"New Value";

Si vous utilisez une sous-classe personnalisée de UITableViewCell, c'est à peu près la même chose, sauf que pour accéder aux vues de la cellule, vous devrez utiliser la propriété contentView.

2
strwils

Il est peut-être possible de placer la cellule dans sa propre section et d'appeler la section de rechargement:

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];

cela semble résoudre le problème partiellement. Ce n’est pas le moyen le plus propre, mais cela peut fonctionner pour vous.

1
Vlad

Dans mon cas similaire, je devais Tweak la mise en œuvre de la méthode

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
...
}

où mes hauteurs ont été réinitialisées. Ainsi, au lieu de réinitialiser la hauteur de chaque cellule, j'ai mis à jour uniquement les cellules affectées pour reloadRowsAtIndexPaths call.

1
zeeawan

J'ai eu le même problème. J'ai fini par appeler simplement tableView.reloadData () à la place après la mise à jour de mes données/cellules et cela n'a pas rebondi vers le haut/les données ont été mises à jour à la place - FYI

0
devjme

Pour construire la réponse de xsee - J'avais défini le Estimate dans le constructeur d'interface sur "automatique". J'ai changé cela en un autre numéro et cela a commencé à fonctionner. J'ai gardé Row Height en automatique.

0
Michael McKenna

Swift 4.2

Cela peut fonctionner n'importe où vous voulez supprimer l'animation . Pendant le rechargement d'un tableau, d'une section de tableau ou de n'importe quelle ligne 

 UIView.performWithoutAnimation({
                cell.configureSelection(isSelected: true)
                tableView.reloadSections([1], with: .none)
                tableView.allowsSelection =  false

            })
0
Tanvir Singh

Si vous connaissez la hauteur minimale de votre cellule, vous devez spécifier cela lors du paramétrage de estimatedRowHeight. Je mettais à 1 comme j'ai lu quelque part auparavant que toute valeur supérieure à 0 suffirait, mais c'était le coupable.

Lorsque je l'ai réglé à 44, hauteur minimale de ma cellule, tout s'est bien passé.

Les hauteurs dynamiques fonctionnaient également très bien, aucun problème avec ce correctif.

0
nr5