¿Es posible actualizar un solo UITableViewCell en un UITableView?


182

Tengo una costumbre UITableViewusando UITableViewCells. Cada uno UITableViewCelltiene 2 botones. Al hacer clic en estos botones, cambiará una imagen UIImageViewdentro de la celda.

¿Es posible actualizar cada celda por separado para mostrar la nueva imagen? Cualquier ayuda es apreciada.

Respuestas:


323

Una vez que tenga el indexPath de su celda, puede hacer algo como:

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

En Xcode 4.6 y superior:

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

Puedes configurar lo que quieras como efecto de animación, por supuesto.


44
Nitpicking aquí, pero, por supuesto, si solo estuviera actualizando una sola celda, probablemente querría usar [NSArray arrayWithObject:]en su lugar.
— Leo Cassarani

57
Además, en esta situación, los beginUpdatesy endUpdatesson innecesarios.
— kubi

2
El OP no está animando nada, por lo que no es necesario llamar a las fechas de inicio / finalización
— kubi

2
Mientras el método no diga obsoleto en la última versión pública de Xcode, todas las versiones de iOS deberían estar bien.
— Alejandro Iván

1
@Supertecnoboff verdadero, pero en algún momento podría ser reemplazado o cambiará su comportamiento. Es mejor manejar las deprecaciones lo antes posible
— Alejandro Iván

34

Intenté simplemente llamar -[UITableView cellForRowAtIndexPath:], pero eso no funcionó. Pero, lo siguiente funciona para mí, por ejemplo. Yo allocy releaseel NSArraypara la gestión de la memoria apretada.

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

¿Es necesario [lanzamiento de indexPaths] aquí? Pensé que solo necesitabas eso si asignabas el objeto tú mismo.
— powerj1984

44
Él asignó la matriz indexPaths. Pero la mejor pregunta es por qué piensa que es necesaria una "administración de memoria estricta". Autorelease hará el trabajo perfectamente bien aquí.
— 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()
}

¿Dónde llamar a este método?
— Master AgentX

18

reloadRowsAtIndexPaths:está bien, pero aún obligará a los UITableViewDelegatemétodos a disparar.

El enfoque más simple que puedo imaginar es:

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

Es importante invocar su configureCell:implementación en el subproceso principal, ya que no funcionará en un subproceso que no sea UI (la misma historia con reloadData/ reloadRowsAtIndexPaths:). A veces puede ser útil agregar:

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

También vale la pena evitar el trabajo que se realizaría fuera de la vista actualmente visible:

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

¿Por qué no quieres que se llame al delegado?
— kernix

Este es el mejor enfoque, ya que no obliga a la vista de tabla a desplazarse hasta la parte superior en lugar de reloadRowsAtIndexPaths: o métodos reloadData.
— ZviBar

Hice esto y terminé siendo atrapado por el hecho de que la celda fue reciclada
— Travelling Man

16

Si está utilizando TableViewCells personalizados, el genérico

[self.tableView reloadData];    

no responde efectivamente esta pregunta a menos que abandone la vista actual y regrese. Tampoco la primera respuesta.

Para recargar con éxito su primera celda de vista de tabla sin cambiar de vista , use el siguiente 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];
}

Inserte el siguiente método de actualización que llama al método anterior para que pueda volver a cargar de forma personalizada solo la celda superior (o la vista de tabla completa si lo desea):

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

    //finish refreshing 
    [refreshControl endRefreshing];
}

Ahora que tiene eso ordenado, dentro de su viewDidLoadagregar lo siguiente:

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

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

[self.tableView addSubview:refreshControl];

Ahora tiene una función de tabla de actualización personalizada que volverá a cargar la celda superior. Para volver a cargar toda la tabla, agregue el

[self.tableView reloadData]; a su nuevo método de actualización.

Si desea volver a cargar los datos cada vez que cambia de vista, implemente el 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

Solo para actualizar estas respuestas ligeramente con la nueva sintaxis literal en iOS 6: puede usar Paths = @ [indexPath] para un solo objeto, o Paths = @ [indexPath1, indexPath2, ...] para varios objetos.

Personalmente, he encontrado que la sintaxis literal para matrices y diccionarios es inmensamente útil y ahorra mucho tiempo. Es más fácil de leer, por un lado. Y elimina la necesidad de un cero al final de cualquier lista de objetos múltiples, que siempre ha sido un bugaboo personal. Todos tenemos nuestros molinos de viento para inclinar, ¿sí? ;-)

Solo pensé en tirar esto en la mezcla. Espero eso ayude.


Di Greg, ¿cuál es realmente un ejemplo de esa sintaxis allí, por favor? ¡Gracias!
— Fattie

3

Aquí hay una extensión 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()
    }

}

Llamar con

self.tableView.updateRow(row: 1)

0

Necesito la celda de actualización pero quiero cerrar el teclado. Si yo uso

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

el teclado desaparece

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.