É possível atualizar um único UITableViewCell em um UITableView?


182

Eu tenho um costume UITableViewusando UITableViewCells. Cada um UITableViewCelltem 2 botões. Clicar nesses botões alterará uma imagem dentro de uma UIImageViewcélula.

É possível atualizar cada célula separadamente para exibir a nova imagem? Qualquer ajuda é apreciada.

Respostas:


323

Depois de ter o indexPath do seu celular, você pode fazer algo como:

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

No Xcode 4.6 e superior:

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

Você pode definir o que quiser como efeito de animação, é claro.


4
Clique aqui, mas é claro que se você estivesse atualizando apenas uma única célula, provavelmente desejaria usar [NSArray arrayWithObject:].
Leo Cassarani

57
Além disso, nessa situação, os beginUpdatese endUpdatessão desnecessários.
kubi

2
O OP não está animando nada, por isso não há necessidade de chamar o endupdates começar /
Kubi

2
Contanto que o método não seja descontinuado na última versão pública do Xcode, todas as versões do iOS devem funcionar.
Alejandro Iván

1
@Supertecnoboff true, mas em algum momento pode ser substituído ou mudará seu comportamento. É melhor depreciações punho o mais cedo possível
Alejandro Iván

34

Tentei ligar -[UITableView cellForRowAtIndexPath:], mas isso não funcionou. Mas, o seguinte funciona para mim, por exemplo. Eu alloce releaseo NSArraypara gerenciamento de memória apertado.

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

O [indexPaths release] é necessário aqui? Eu pensei que você só precisava disso se alocasse o objeto você mesmo.
precisa saber é o seguinte

4
Ele alocou a matriz indexPaths. Mas a melhor pergunta é por que ele acha que "gerenciamento de memória rígido" é necessário. O Autorelease fará o trabalho perfeitamente bem aqui.
John Cromartie

22

Rápido:

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

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

Onde chamar esse método?
Master AgentX 27/02/19

18

reloadRowsAtIndexPaths:está bem, mas ainda forçará os UITableViewDelegatemétodos a serem disparados.

A abordagem mais simples que posso imaginar é:

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

É importante chamar sua configureCell:implementação no thread principal, pois ele não funcionará no thread que não seja da interface do usuário (a mesma história com reloadData/ reloadRowsAtIndexPaths:). Às vezes, pode ser útil adicionar:

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

Também vale a pena evitar o trabalho que seria feito fora da visualização atualmente visível:

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

Por que você não gostaria que o delegado fosse chamado?
Kernix 27/07/2015

Essa é a melhor abordagem, pois não força a exibição de tabela a rolar até o topo, em oposição aos métodos reloadRowsAtIndexPaths: ou reloadData.
ZviBar

Eu fiz isso e acabou sendo pego pelo fato de que a célula foi reciclado
Travelling Man

16

Se você estiver usando TableViewCells personalizados, o genérico

[self.tableView reloadData];    

não responde efetivamente a essa pergunta, a menos que você saia da visualização atual e volte. Nem a primeira resposta.

Para recarregar com êxito sua primeira célula de exibição de tabela sem alternar exibições , use o seguinte código:

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

Insira o seguinte método de atualização, que chama o método acima, para que você possa recarregar apenas a célula superior (ou a visualização da tabela inteira, se desejar):

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

    //finish refreshing 
    [refreshControl endRefreshing];
}

Agora que você ordenou isso, dentro do seu viewDidLoadadicione o seguinte:

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

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

[self.tableView addSubview:refreshControl];

Agora você tem um recurso personalizado da tabela de atualização que recarregará a célula superior. Para recarregar a tabela inteira, adicione o

[self.tableView reloadData]; ao seu novo método de atualização.

Se você deseja recarregar os dados toda vez que alternar as visualizações, implemente o método:

//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

Apenas para atualizar um pouco essas respostas com a nova sintaxe literal no iOS 6 - você pode usar Paths = @ [indexPath] para um único objeto ou Paths = @ [indexPath1, indexPath2, ...] para vários objetos.

Pessoalmente, descobri que a sintaxe literal de matrizes e dicionários é imensamente útil e economiza muito tempo. É apenas mais fácil de ler, por um lado. E elimina a necessidade de nada no final de qualquer lista de vários objetos, que sempre foi um bugaboo pessoal. Todos nós temos nossos moinhos de vento para inclinar, sim? ;-)

Só pensei em jogar isso na mistura. Espero que ajude.


Diga Greg, o que é realmente um exemplo dessa sintaxe, por favor? Obrigado!
Fattie

3

Aqui está uma extensão do UITableView com o 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()
    }

}

Ligue com

self.tableView.updateRow(row: 1)

0

Preciso da célula de atualização, mas quero fechar o teclado. Se eu usar

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

o teclado desaparece

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.