È possibile aggiornare un singolo UITableViewCell in un UITableView?


182

Ho un'usanza personalizzata UITableViewusando UITableViewCells. Ognuno UITableViewCellha 2 pulsanti. Facendo clic su questi pulsanti cambierà un'immagine in a UIImageViewall'interno della cella.

È possibile aggiornare ciascuna cella separatamente per visualizzare la nuova immagine? Qualsiasi aiuto è apprezzato.

Risposte:


323

Una volta che hai il indexPath della tua cella, puoi fare qualcosa del tipo:

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

In Xcode 4.6 e versioni successive:

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

Puoi impostare qualunque cosa tu voglia come effetto di animazione, ovviamente.


4
Nitpicking qui, ma ovviamente se stavi solo aggiornando una singola cella, probabilmente vorrai usare [NSArray arrayWithObject:]invece.
Leo Cassarani,

57
Inoltre, in questa situazione, beginUpdatese endUpdatesnon sono necessari.
kubi,

2
L'OP non sta animando nulla, quindi non c'è bisogno di chiamare i dati di inizio / fine
kubi,

2
Finché il metodo non dice deprecato nell'ultima versione Xcode pubblica, tutte le versioni di iOS dovrebbero andare bene.
Alejandro Iván,

1
@Supertecnoboff vero, ma a un certo punto potrebbe essere sostituito o cambierà il suo comportamento. È meglio gestire le deprecazioni al più presto
Alejandro Iván,

34

Ho provato a chiamare -[UITableView cellForRowAtIndexPath:], ma non ha funzionato. Ma, ad esempio, per me funziona. Io alloce releaseil NSArrayper una stretta gestione della memoria.

- (void)reloadRow0Section0 {
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    NSArray *indexPaths = [[NSArray alloc] initWithObjects:indexPath, nil];
    [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
    [indexPaths release];
}

[Release indexPaths] è necessario qui? Pensavo che te ne servisse solo se avessi allocato l'oggetto da solo.
powerj1984,

4
Ha allocato l'array indexPaths. Ma la domanda migliore è perché pensa che sia necessaria una "stretta gestione della memoria". Autorelease farà il lavoro perfettamente bene qui.
John Cromartie,

22

Swift:

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

    tableView.beginUpdates()
    tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) //try other animations
    tableView.endUpdates()
}

Dove chiamare questo metodo?
Master AgentX

18

reloadRowsAtIndexPaths:va bene, ma costringerà comunque i UITableViewDelegatemetodi a sparare.

L'approccio più semplice che posso immaginare è:

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

È importante invocare l' configureCell:implementazione sul thread principale, poiché non funzionerà su thread non UI (la stessa storia con reloadData/ reloadRowsAtIndexPaths:). A volte potrebbe essere utile aggiungere:

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

Vale anche la pena evitare il lavoro che verrebbe svolto al di fuori della vista attualmente visibile:

BOOL cellIsVisible = [[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] != NSNotFound;
if (cellIsVisible)
{
    ....
}

Perché non vuoi che venga chiamato un delegato?
Kernix,

Questo è l'approccio migliore poiché non impone alla vista tabella di scorrere fino in cima rispetto ai metodi reloadRowsAtIndexPaths: o reloadData.
ZviBar,

L'ho fatto e sono stato colto dal fatto che la cella è stata riciclata
Traveling Man

16

Se si utilizzano TableViewCells personalizzati, il generico

[self.tableView reloadData];    

non risponde efficacemente a questa domanda a meno che non abbandoni la vista corrente e torni indietro. Nemmeno la prima risposta.

Per ricaricare correttamente la prima cella della vista tabella senza cambiare vista , utilizzare il codice seguente:

//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];
}

Inserisci il seguente metodo di aggiornamento che chiama il metodo sopra in modo da poter ricaricare in modo personalizzato solo la cella superiore (o l'intera vista della tabella, se lo desideri):

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

    //finish refreshing 
    [refreshControl endRefreshing];
}

Ora che l'hai ordinato, all'interno del tuo viewDidLoadaggiungi quanto segue:

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

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

[self.tableView addSubview:refreshControl];

Ora hai una funzione di tabella di aggiornamento personalizzata che ricaricherà la cella superiore. Per ricaricare l'intera tabella, aggiungi il

[self.tableView reloadData]; al tuo nuovo metodo di aggiornamento.

Se desideri ricaricare i dati ogni volta che cambi visualizzazione, implementa il metodo:

//ensure that it reloads the table view data when switching to this view
- (void) viewWillAppear:(BOOL)animated {
    [self.tableView reloadData];
}

6

Swift 3:

tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()

4

Solo per aggiornare leggermente queste risposte con la nuova sintassi letterale in iOS 6: puoi usare Paths = @ [indexPath] per un singolo oggetto o Paths = @ [indexPath1, indexPath2, ...] per più oggetti.

Personalmente, ho trovato che la sintassi letterale di array e dizionari è immensamente utile e fa risparmiare tempo. È solo più facile da leggere, per prima cosa. E rimuove la necessità di zero alla fine di qualsiasi elenco multi-oggetto, che è sempre stato un bugaboo personale. Tutti abbiamo i nostri mulini a vento con cui inclinare, sì? ;-)

Ho pensato di buttarlo nel mix. Spero che sia d'aiuto.


Di 'Greg, qual è in realtà un esempio di quella sintassi lì, per favore? Grazie!
Fattie,

3

Ecco un'estensione UITableView con 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()
    }

}

Chiama con

self.tableView.updateRow(row: 1)

0

Ho bisogno della cella di aggiornamento ma voglio chiudere la tastiera. Se io uso

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

la tastiera scompare

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.