Est-il possible d'actualiser un seul UITableViewCell dans un UITableView?

182

J'ai une coutume UITableViewutilisant UITableViewCells. Chacun UITableViewCella 2 boutons. Cliquer sur ces boutons changera une image dans une UIImageViewdans la cellule.

Est-il possible de rafraîchir chaque cellule séparément pour afficher la nouvelle image? Toute aide est appréciée.

Assistant d'iOS
la source

Réponses:

323

Une fois que vous avez l'indexPath de votre cellule, vous pouvez faire quelque chose comme:

[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPathOfYourCell, nil] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates]; 

Dans Xcode 4.6 et supérieur:

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

Vous pouvez définir ce que vous voulez comme effet d'animation, bien sûr.

Romain
la source
4
Nitpicking ici, mais bien sûr, si vous n'actualisiez qu'une seule cellule, vous voudriez probablement l'utiliser à la [NSArray arrayWithObject:]place.
Leo Cassarani
57
De plus, dans cette situation, les beginUpdateset endUpdatessont inutiles.
kubi
2
L'OP n'anime rien, il n'est donc pas nécessaire d'appeler les mises à jour de début / de fin
kubi
2
Tant que la méthode ne dit pas obsolète dans la dernière version publique de Xcode, toutes les versions iOS devraient fonctionner.
Alejandro Iván
1
@Supertecnoboff true, mais à un moment donné, il pourrait être remplacé ou modifiera son comportement. Il vaut mieux gérer les dépréciations dès que possible
Alejandro Iván
34

J'ai essayé d'appeler -[UITableView cellForRowAtIndexPath:], mais cela n'a pas fonctionné. Mais, ce qui suit fonctionne pour moi par exemple. I allocet releasele NSArraypour une gestion serrée de la mémoire.

- (void)reloadRow0Section0 {
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    NSArray *indexPaths = [[NSArray alloc] initWithObjects:indexPath, nil];
    [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
    [indexPaths release];
}
ma11hew28
la source
[IndexPaths release] est-il nécessaire ici? Je pensais que vous n'en aviez besoin que si vous allouiez l'objet vous-même.
powerj1984
4
Il a alloué le tableau indexPaths. Mais la meilleure question est de savoir pourquoi il pense qu'une "gestion serrée de la mémoire" est nécessaire. Autorelease fera parfaitement bien le travail ici.
John Cromartie
22

Rapide:

func updateCell(path:Int){
    let indexPath = NSIndexPath(forRow: path, inSection: 1)

    tableView.beginUpdates()
    tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) //try other animations
    tableView.endUpdates()
}
Esqarrouth
la source
Où appeler cette méthode?
Master AgentX
18

reloadRowsAtIndexPaths:est bien, mais forcera toujours les UITableViewDelegateméthodes à tirer.

L'approche la plus simple que je puisse imaginer est:

UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
[self configureCell:cell forIndexPath:indexPath];

Il est important d'appeler votre configureCell:implémentation sur le thread principal, car cela ne fonctionnera pas sur un thread non-UI (la même histoire avec reloadData/ reloadRowsAtIndexPaths:). Parfois, il peut être utile d'ajouter:

dispatch_async(dispatch_get_main_queue(), ^
{
    [self configureCell:cell forIndexPath:indexPath];
});

Il vaut également la peine d'éviter tout travail qui serait effectué en dehors de la vue actuellement visible:

BOOL cellIsVisible = [[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] != NSNotFound;
if (cellIsVisible)
{
    ....
}
Maciek Czarnik
la source
Pourquoi ne voudriez-vous pas que le délégué soit appelé?
kernix
C'est la meilleure approche car elle ne force pas la vue table à défiler jusqu'en haut par opposition aux méthodes reloadRowsAtIndexPaths: ou reloadData.
ZviBar
J'ai fait cela et j'ai fini par être surpris par le fait que la cellule était recyclée
Travelling Man
16

Si vous utilisez des TableViewCells personnalisées, le générique

[self.tableView reloadData];    

ne répond pas efficacement à cette question sauf si vous quittez la vue actuelle et y revenez. La première réponse non plus.

Pour recharger correctement votre première cellule de vue de tableau sans changer de vue , utilisez le code suivant:

//For iOS 5 and later
- (void)reloadTopCell {
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    NSArray *indexPaths = [[NSArray alloc] initWithObjects:indexPath, nil];
    [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
}

Insérez la méthode d'actualisation suivante qui appelle la méthode ci-dessus afin que vous puissiez recharger uniquement la cellule supérieure (ou la vue de tableau entière si vous le souhaitez):

- (void)refresh:(UIRefreshControl *)refreshControl {
    //call to the method which will perform the function
    [self reloadTopCell];

    //finish refreshing 
    [refreshControl endRefreshing];
}

Maintenant que vous avez trié, à l'intérieur de votre viewDidLoadajoutez ce qui suit:

//refresh table view
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];

[refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];

[self.tableView addSubview:refreshControl];

Vous disposez désormais d'une fonction de table d'actualisation personnalisée qui rechargera la cellule supérieure. Pour recharger la table entière, ajoutez le

[self.tableView reloadData]; à votre nouvelle méthode d'actualisation.

Si vous souhaitez recharger les données à chaque fois que vous changez de vue, implémentez la méthode:

//ensure that it reloads the table view data when switching to this view
- (void) viewWillAppear:(BOOL)animated {
    [self.tableView reloadData];
}
Développeur d'applications
la source
6

Swift 3:

tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
ergunkocak
la source
4

Juste pour mettre à jour légèrement ces réponses avec la nouvelle syntaxe littérale dans iOS 6 - vous pouvez utiliser Paths = @ [indexPath] pour un seul objet ou Paths = @ [indexPath1, indexPath2, ...] pour plusieurs objets.

Personnellement, j'ai trouvé que la syntaxe littérale des tableaux et des dictionnaires était extrêmement utile et économisait beaucoup de temps. C'est juste plus facile à lire, d'une part. Et cela supprime le besoin d'un nul à la fin de toute liste multi-objets, qui a toujours été un bugaboo personnel. Nous avons tous nos moulins à vent avec lesquels basculer, n'est-ce pas? ;-)

Je pensais juste que je jetterais ça dans le mélange. J'espère que ça aide.

Gregory Hill
la source
Dites Greg, quel est en fait un exemple de cette syntaxe, s'il vous plaît? Merci!
Fattie
3

Voici une extension UITableView avec Swift 5:

import UIKit

extension UITableView
{    
    func updateRow(row: Int, section: Int = 0)
    {
        let indexPath = IndexPath(row: row, section: section)

        self.beginUpdates()
        self.reloadRows(at: [indexPath as IndexPath], with: UITableView.RowAnimation.automatic)
        self.endUpdates()
    }

}

Appeler avec

self.tableView.updateRow(row: 1)
iphaaw
la source
0

J'ai besoin de la cellule de mise à niveau mais je veux fermer le clavier. Si j'utilise

let indexPath = NSIndexPath(forRow: path, inSection: 1)
tableView.beginUpdates()
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) //try other animations
tableView.endUpdates()

le clavier disparaît


la source