2012-10-02 36 views
15

Tengo un UITableViewCell que se selecciona cuando se toca. Durante este estado seleccionado, si el usuario toca la celda nuevamente, quiero que la celda se deseleccione.UITableView toque para anular la selección de la celda

No puedo encontrar ninguna de las llamadas de delegados que se golpean. ¿Alguna idea de cómo implementar esto? ¿Realmente va a ser un reconocedor de gestos?

Respuesta

-4

Tal vez mi pregunta no era lo suficientemente específica, pero las dos respuestas son un poco más amplia de lo que yo buscaba.

Parece que esto no es posible, y fui con un reconocedor de gestos de la celda para establecer manualmente el estado seleccionado/no seleccionado.

+0

¿Qué usted realmente quiere hacer? Mi código le da la capacidad de rastrear que la celda ha sido seleccionada antes o no. Dentro de esa declaración if puedes implementar más cosas que quieras. – JHHoang

+0

Si la celda ya está seleccionada, este método nunca se llama –

+0

Es fácil. ¿Cuántas celdas tienes? Puedo escribirle un código de muestra con una celda usando el delegado de UItableview. Avísame si todavía te interesan. – JHHoang

2

Cuando selecciona una celda, se activa este método delegado.

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


     UITableViewCell *theUITableViewCell = [tableView cellForRowAtIndexPath:path]; 
     if (theUITableViewCell.selected == YES){ 
      self.tableView deselectRowAtIndexPath:<#(NSIndexPath *)#> animated:<#(BOOL)#> 
      // Do more thing 
     }else{ 
      // By default, it is highlighted for selected state 
     } 

} 

Es un pseudo código.

3

Creo que el uso del color de selección azul para alternar puede dar una impresión extraña. ¿Por qué no usar un accesorio como una marca de verificación? Esta es una técnica mucho más familiar para el alternar selección (ya sea multicelda o de celda única).

Ver esta respuesta para obtener información: UITableView Multiple Selection

2

Puede probar esto, es que funciona para mí (por única selección o selecciones múltiples):

A. asignar un NSMutableArray privado en viewDidLoad como:

@interface XXXViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> 
{ 
    NSMutableArray * selectedZoneCellIndexPaths; 
} 


- (void)viewDidLoad 
{ 
    selectedZoneCellIndexPaths = [[NSMutableArray alloc] init]; 
} 

B. en UITableViewDelegate didSelectRow añadir siguientes líneas

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

    for (NSIndexPath * iter in selectedZoneCellIndexPaths) 
    { 
     if (indexPath.section == iter.section && indexPath.row == iter.row) 
     { 
      [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
      [selectedZoneCellIndexPaths removeObject:iter]; 
      return; 
     } 
    } 
    [selectedZoneCellIndexPaths addObject:indexPath]; 
    return; 
} 
+0

Esto causará errores si no maneja la eliminación de células correctamente –

30

en realidad se puede hacer esto utilizando el método delegado willSelectRowAtIndexPath:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
    if ([cell isSelected]) { 
     // Deselect manually. 
     [tableView.delegate tableView:tableView willDeselectRowAtIndexPath:indexPath]; 
     [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
     [tableView.delegate tableView:tableView didDeselectRowAtIndexPath:indexPath]; 

     return nil; 
    } 

    return indexPath; 
} 

Tenga en cuenta que deselectRowAtIndexPath: no llamará a los métodos de delegado automáticamente, por lo que debe realizar esas llamadas manualmente.

+9

Tenga en cuenta que siempre debe verificar si el delegado responde a un selector antes de llamar a un método en él. – Patrick

4

Aquí es una solución aún mejor:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if ([[tableView indexPathForSelectedRow] isEqual:indexPath]) { 
     [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
     return nil; 
    } 
    return indexPath; 
} 
+0

No use == para comparar objetos. Esto debería ser si ([[tableView indexPathForSelectedRow] isEqual: indexPath]) { – ahwulf

0

que fue después de lo mismo, pero @occulus' answer me dio la pista que me estaba perdiendo.

Me di cuenta de que la manera de hacerlo es permitir la selección múltiple en la vista de tabla y deseleccionar manualmente las filas seleccionadas previamente cuando se selecciona una nueva fila usando uno de los métodos de delegado.

Parece bastante natural que en el modo de selección única, la vista de tabla intente dejar una fila seleccionada tanto como sea posible, por lo que no se anula la selección al tocar una fila seleccionada.

3
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
    if ([cell isSelected]) { 
     // Deselect manually. 
     if ([tableView.delegate respondsToSelector:@selector(tableView:willDeselectRowAtIndexPath:)]) { 
      [tableView.delegate tableView:tableView willDeselectRowAtIndexPath:indexPath]; 
     } 
     [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
     if ([tableView.delegate respondsToSelector:@selector(tableView:didDeselectRowAtIndexPath:)]) { 
      [tableView.delegate tableView:tableView didDeselectRowAtIndexPath:indexPath]; 
     } 
     return nil; 
    } 

    return indexPath; 
} 
7

en Swift 4:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { 

    if let indexPathForSelectedRow = tableView.indexPathForSelectedRow, 
     indexPathForSelectedRow == indexPath { 
     tableView.deselectRow(at: indexPath, animated: false) 
     return nil 
    } 
    return indexPath 
} 
1

versión Swift de la respuesta de prisonerjohn:

public func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? { 
    let cell = tableView.cellForRowAtIndexPath(indexPath) 
    if (cell?.selected ?? false) { 
    // Deselect manually. 
    tableView.delegate!.tableView?(tableView, willDeselectRowAtIndexPath: indexPath) 
    tableView.deselectRowAtIndexPath(indexPath, animated: true) 
    tableView.delegate!.tableView?(tableView, didDeselectRowAtIndexPath: indexPath) 
    return nil 
    } 
return indexPath; 
} 
2

Cuando se utiliza el modo "Selección múltiple", "didSelectRowAtIndexPath" no se llama cuando hace clic en un fila que ya está seleccionada. Todavía se puede seleccionar más de una fila programáticamente en el modo "Selección única" y las filas activarán didSelectRowAtIndexPath en todos los clics.

Solo un aviso a alguien que estaba teniendo los mismos problemas.

1

De @prisonerjohn, en caso de que alguien se pregunta cómo comprobar si el delegado responde al selector como dijo @Patrick, en Swift 3:

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { 
    guard let cell = tableView.cellForRow(at: indexPath) else { 
     // Handle invalid cell 
     ... 
    } 

    if cell.isSelected { 
     if let respond = tableView.delegate?.responds(
      to: #selector(tableView(_:willDeselectRowAt:))), 
      respond == true { 
      tableView.delegate?.tableView!(tableView, willDeselectRowAt: indexPath) 
     } 

     tableView.deselectRow(at: indexPath, animated: true) 

     if let respond = tableView.delegate?.responds(
      to: #selector(tableView(_:didDeselectRowAt:))), 
      respond == true { 
      tableView.delegate?.tableView!(tableView, didDeselectRowAt: indexPath) 
     } 

     return nil 
    } 

    return indexPath 
} 
+0

Recibo el siguiente error: 'Uso del identificador no resuelto 'tableView (_: willDeselectRowAt :)''. Usando XCode9.1 y Swift3 – elysch

Cuestiones relacionadas