Czy można odświeżyć pojedynczy UITableViewCell w UITableView?

187

Mam niestandardowy UITableViewprzy użyciu UITableViewCells. Każdy UITableViewCellma 2 przyciski. Kliknięcie tych przycisków spowoduje zmianę obrazu w UIImageViewkomórce.

Czy można odświeżyć każdą komórkę osobno, aby wyświetlić nowy obraz? Każda pomoc jest mile widziana.

Kreator iOS
źródło

Odpowiedzi:

328

Gdy masz już indexPath swojej komórki, możesz zrobić coś takiego:

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

W Xcode 4.6 i nowszych:

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

Oczywiście możesz ustawić dowolny efekt animacji.

Romain
źródło
4
Nitpicking tutaj, ale oczywiście gdybyś odświeżył tylko jedną komórkę, której prawdopodobnie chciałbyś użyć [NSArray arrayWithObject:].
Leo Cassarani,
58
Również w tej sytuacji beginUpdatesi endUpdatessą zbędne.
kubi
2
PO nie jest animowanie nic, więc nie ma potrzeby, aby wywołać rozpocząć / endupdates
Kubi
2
Dopóki metoda nie mówi, że jest przestarzała w ostatniej publicznej wersji Xcode, wszystkie wersje iOS powinny być w porządku.
Alejandro Iván
1
@Supertecnoboff prawda, ale w pewnym momencie może zostać zastąpione lub zmieni swoje zachowanie. Lepiej radzić sobie z wycofaniami jak najszybciej
Alejandro Iván
34

Próbowałem po prostu zadzwonić -[UITableView cellForRowAtIndexPath:], ale to nie zadziałało. Ale na przykład działa dla mnie następujące. Ja alloci za ciasno zarządzanie pamięcią.releaseNSArray

- (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
źródło
Czy [zwolnienie indexPaths] jest tutaj konieczne? Myślałem, że potrzebujesz tego tylko wtedy, gdy sam przydzieliłeś obiekt.
powerj1984
4
Przydzielił tablicę indexPaths. Ale lepszym pytaniem jest, dlaczego uważa, że ​​„ścisłe zarządzanie pamięcią” jest konieczne. Autorelease wykona tutaj zadanie doskonale.
John Cromartie,
22

Szybki:

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
źródło
Gdzie nazwać tę metodę?
Master AgentX
18

reloadRowsAtIndexPaths:jest w porządku, ale nadal będzie wymuszać UITableViewDelegatemetody strzelania.

Najprostsze podejście, jakie mogę sobie wyobrazić, to:

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

To ważne , aby wywołać swoją configureCell:realizację na głównym wątku, jak to przyzwyczajenie praca na wątku non-UI (tej samej historii z reloadData/ reloadRowsAtIndexPaths:). Czasami pomocne może być dodanie:

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

Warto też unikać pracy, która byłaby wykonywana poza aktualnie widocznym widokiem:

BOOL cellIsVisible = [[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] != NSNotFound;
if (cellIsVisible)
{
    ....
}
Maciek Czarnik
źródło
Dlaczego nie chcesz, aby wzywano delegata?
kernix
Jest to najlepsze podejście, ponieważ nie wymusza przewijania widoku tabeli do samego początku w przeciwieństwie do metod reloadRowsAtIndexPaths: lub reloadData.
ZviBar
Zrobiłem to i zostałem złapany przez fakt, że komórka została poddana recyklingowi
Traveling Man
16

Jeśli używasz niestandardowych TableViewCells, ogólny

[self.tableView reloadData];    

nie odpowie skutecznie na to pytanie, chyba że opuścisz bieżący widok i wrócisz. Pierwsza odpowiedź też nie.

Aby pomyślnie ponownie załadować pierwszą komórkę widoku tabeli bez przełączania widoków , użyj następującego kodu:

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

Wstaw następującą metodę odświeżania, która wywołuje powyższą metodę, dzięki czemu możesz ponownie załadować tylko górną komórkę (lub cały widok tabeli, jeśli chcesz):

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

    //finish refreshing 
    [refreshControl endRefreshing];
}

Teraz, gdy masz już to posortowane, wewnątrz viewDidLoaddodaj następujące elementy:

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

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

[self.tableView addSubview:refreshControl];

Masz teraz niestandardową funkcję odświeżania tabeli, która ponownie załaduje górną komórkę. Aby ponownie załadować całą tabelę, dodaj plik

[self.tableView reloadData]; do nowej metody odświeżania.

Jeśli chcesz przeładowywać dane za każdym razem, gdy przełączasz widoki, zaimplementuj metodę:

//ensure that it reloads the table view data when switching to this view
- (void) viewWillAppear:(BOOL)animated {
    [self.tableView reloadData];
}
App Dev Guy
źródło
6

Swift 3:

tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
ergunkocak
źródło
4

Wystarczy nieznacznie zaktualizować te odpowiedzi za pomocą nowej składni literału w iOS 6 - możesz użyć Paths = @ [indexPath] dla pojedynczego obiektu lub Paths = @ [indexPath1, indexPath2, ...] dla wielu obiektów.

Osobiście odkryłem, że dosłowna składnia tablic i słowników jest niezwykle użyteczna i pozwala zaoszczędzić dużo czasu. Po pierwsze, jest po prostu łatwiejszy do odczytania. I eliminuje potrzebę umieszczania zera na końcu każdej listy wielu obiektów, co zawsze było osobistym błędem. Wszyscy mamy wiatraki, którymi możemy się przechylić, tak? ;-)

Pomyślałem, że dodam to do miksu. Mam nadzieję, że to pomoże.

Gregory Hill
źródło
Powiedz Greg, jaki właściwie jest przykład tej składni, proszę? Dzięki!
Fattie
3

Oto rozszerzenie UITableView ze 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()
    }

}

Zadzwoń z

self.tableView.updateRow(row: 1)
iphaaw
źródło
0

Potrzebuję komórki uaktualnienia, ale chcę zamknąć klawiaturę. Jeśli używam

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

klawiatura zniknie


źródło