¿Por qué UITableViewCell permanece resaltado?


145

¿Qué haría que una celda de vista de tabla permanezca resaltada después de ser tocada? Hago clic en la celda y puedo ver que permanece resaltada mientras se empuja una vista detallada. Una vez que aparece la vista de detalle, la celda sigue resaltada.

Respuestas:


262

En su didSelectRowAtIndexPathnecesita llamar deselectRowAtIndexPathpara anular la selección de la celda.

Entonces, sea lo que sea que esté haciendo didSelectRowAtIndexPath, simplemente haga que llame deselectRowAtIndexPathtambién.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 // Do some stuff when the row is selected
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

11
Prefiero llamar deselectRowAtIndexPatha mi viewDidAppear, si selecciono la fila aparece una nueva vista.
notnoop 03 de

55
En realidad, ese no es el lugar correcto para llamarlo, realmente ... intente usar una aplicación de Apple con tablas (Contactos es una buena opción) y verá que después de salir a una nueva pantalla, al regresar, la celda aún está resaltada brevemente antes de ser deseleccionado. En teoría, creo que usted no tiene que hacer ningún trabajo extra para tener que anular la selección de inmediato por su propia cuenta, por lo que no se necesita el código en viewDidAppear ...
Kendall Helmstetter Gelner

66
@Kendall, @ 4thSpace: Quizás mi último comentario fue confuso sobre a quién me refería, disculpas por eso. UITableViewController llama al -deselectRowAtIndexPath:animated:método en su propiedad tableView desde -viewDidAppear. Sin embargo, si tiene una vista de tabla en una subclase de UIViewController, debe llamar -deselectRowAtIndexPath:animated:desde -viewDidAppearusted mismo. :)
Daniel Tull el

55
En mi subclase de UITableViewController, en realidad fue una anulación de -viewWillAppear:eso lo rompió. Agregar una llamada para [super viewWillAppear:animated]que funcione nuevamente.
Ben Challenor

55
Dado que 3.2, el comportamiento automático anulación de la selección se produce si su UITableViewController's clearsSelectionOnViewWillAppearpropiedad se establece en YES(que es el valor por defecto), y no se ha impedido [super viewWillAppear]de ser llamado.
Desfragmentado el

62

La forma más limpia de hacerlo es a la vista

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // Unselect the selected row if any
    NSIndexPath*    selection = [self.tableView indexPathForSelectedRow];
    if (selection) {
        [self.tableView deselectRowAtIndexPath:selection animated:YES];
    }
}

De esta manera, tiene la animación de desvanecer la selección cuando regrese al controlador, como debería ser.

Tomado de http://forums.macrumors.com/showthread.php?t=577677

Versión rápida

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // deselect the selected row if any
    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRowNotNill = selectedRow {
        tableView.deselectRow(at: selectedRowNotNill, animated: true)
    }
}

1
Este es el que espero que la mayoría de la gente quiera si no usa un UITableViewController. +1
MikeB

3
Me pregunto qué está haciendo la gente ahora que iOS 7 permite al usuario 'arrastrar' hacia atrás. Arrastrando parcialmente pero luego no completando la acción activará viewWillAppear. Cuando el usuario regrese de verdad, la fila no será seleccionada.
Ben Packard

1
@BenPackard solo lo llama en su viewDidAppearlugar.
squarefrog

@Jessica La indexPathForSelectedRowllamada puede volver nula, por lo que debe verificarse. La documentación indica : Una ruta de índice que identifica los índices de fila y sección de la fila seleccionada, o nula si la ruta de índice no es válida.
Gordonium

Esto debería ser una respuesta aceptada, es más amigable con la interfaz de usuario para que el usuario pueda llegar a la selección después de regresar, perfecto 👌
Yahya Alshaar

20

¿Subclase -(void)viewWillAppear:(BOOL)animated? El UITableViewCell seleccionado no deseleccionará cuando no llame [super viewWillAppear:animated];a su método personalizado.


19

Para los usuarios de Swift, agregue esto a su código:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

Es la respuesta de paulthenerd, excepto en Swift en lugar de Obj-C.


1
¿no se deselecciona por sí solo, me refiero al momento en que lo sueltas?
Miel

@Honey Posiblemente así en una versión anterior de iOS, o al desaparecer la vista, pero ciertamente no ahora en iOS 10 (probablemente incluso antes) y superiores.
Jamie Birch

9

Solución Swift 3

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}

7

Si está utilizando un UITableViewCell, comente la siguiente línea

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{

 // [super setSelected:selected animated:animated];

}

Espero que esto ayude.


4

Actualizado con Swift 4

Después de algunos experimentos, también basados ​​en respuestas anteriores, tengo la conclusión de que el mejor comportamiento se puede lograr de 2 maneras: (casi idéntico en la práctica)

// First Solution: delegate of the table View
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: false)
}

// Second Solution: With the life cycle of the view.
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        tableView.deselectRow(at: selectedRow, animated: false)
    }
}

Personalmente, estoy adoptando la primera solución, porque es simplemente más conciso. Otra posibilidad, si necesita un poco de animación cuando regrese a su tableView, es usar viewWillAppear:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let selectedRow: IndexPath? = _view.tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        _view.tableView.deselectRow(at: selectedRow, animated: true)
    }
}

Por último, pero no menos importante, si está utilizando un UITableViewController, también puede aprovechar la propiedad clearsSelectionOnViewWillAppear .


3

Para obtener el comportamiento que Kendall Helmstetter Gelner describe en su comentario, es probable que no desee deseleccionarRowAtIndexPath sino la propiedad clearSsectionOnViewWillAppear en su controlador. ¿Quizás esto se estableció en SÍ por accidente?

Vea el comentario en la plantilla predeterminada de Apple para las nuevas subclases UITableViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
}

2

También recibí este problema para mi aplicación de desglose. Después de que un viewcontroller, que llamaré VC, regrese después de presionar otro ViewController, la celda seleccionada en VC permaneció resaltada. En mi aplicación, había creado VC para manejar el segundo nivel (de tres niveles) de mi desglose.

El problema en mi caso es que VC era un UIViewController (que contenía una Vista que contenía un TableView). En su lugar, hice de VC un UITableViewController (que contenía un TableView). La clase UITableViewController maneja automáticamente el resaltado de la celda de la tabla después de regresar de una inserción. La segunda respuesta a la publicación " Problema con deselectRowAtIndexPath en tableView " ofrece una respuesta más completa a este problema.

El problema no se produjo para el controlador de vista raíz porque cuando creé la aplicación como una "Aplicación basada en navegación" en XCode, el controlador de vista raíz resultante ya estaba hecho en la subclase UITableViewController.


1

Si ninguno de estos funciona para usted, considere esta solución alternativa:

Use una secuencia de desconexión para llamar:

@IBAction func unwind_ToTableVC (segue: UIStoryboardSegue) {
    if let index = tableView.indexPathForSelectedRow {
        tableView.deselectRowAtIndexPath(index, animated: true)
    }
}

¿Por qué hacer esto? Principalmente si tiene problemas para ejecutar el código de deselección en el momento adecuado. Tuve problemas con que no funcionara en la vista Aparecerá así que el desenrollado funcionó mucho mejor.

Pasos:

  1. Escriba la secuencia de desenrollado (o pegue desde arriba) en su primer VC (el que está en la tabla)

  2. Ir a la segunda VC. Control-arrastre desde el botón Cancelar / Listo / Etc que está utilizando para descartar ese VC y arrastre hasta el ícono Salir en la parte superior.

  3. Seleccione el desenrollar segue que creó en el paso 1

    Buena suerte.


Esta es la mejor solución para los momentos en que viewDidAppear no se activa (es decir, si la vista secundaria se presenta modalmente como una hoja de formulario y no cubre toda la pantalla).
pheedsta

1

Estoy usando CoreData, por lo que el código que funcionó para mí fue una combinación de ideas de varias respuestas, en Swift:

override func viewDidAppear(_ animated: Bool) {
    if let testSelected = yourTable.indexPathForSelectedRow {
        yourTable.deselectRow(at: testSelected, animated: true)
    }
    super.viewDidAppear(true)
}

1
 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}

0

He tenido el mismo problema durante mucho tiempo, así que en caso de que alguien más esté luchando:

Eche un vistazo a su -tableView: cellForRowAtIndexPath:y vea si está creando celdas o está utilizando un 'identificador de reutilización'. Si es esto último, asegúrese de que su tabla en IB tenga una celda con ese identificador. Si no está utilizando un identificador de reutilización, simplemente cree una nueva celda para cada fila.

Esto debería dar a su tabla la 'fila seleccionada desvanecida' esperada al aparecer.


0

Use este método en la clase UITableViewCell

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

   // Just comment This line of code
   // [super setSelected:selected animated:animated];        
}

0

Para Swift 3: preferiría que se use en viewDidDisappear

Definir:-

    var selectedIndexPath = IndexPath()

En viewDidDisappear: -

    override func viewDidDisappear(_ animated: Bool) {
    yourTableView.deselectRow(at: selectedIndexPath, animated: true)
}

En didSelectRowAtIndexPath: -

    func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
    selectedIndexPath = indexPath
}

0

si la celda permanece resaltada después de tocarla, puede llamar al método UITabelView,

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

`[tableView deselectRowAtIndexPath:indexPath animated:YES];`   

}

O bien, puede usar el siguiente método y modificarlo según sus requisitos,

// MARK: UITableViewDelegate

func tableView(tableView: UITableView, didHighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.greenColor()
  }
}

func tableView(tableView: UITableView, didUnhighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.blackColor()
  }
} 

0

Xcode 10, Swift 4

Tuve este mismo problema y descubrí que dejé una llamada vacía para verWillAppear en la parte inferior de mi tableViewController. Una vez que eliminé la función de anulación vacía, la fila ya no permaneció resaltada al regresar a la vista tableView.

problema func

override func viewWillAppear(_ animated: Bool) {
  // need to remove this function if not being used.
}

eliminar la función vacía resolvió mi problema.


0

Solución Swift 5:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
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.