iOS UITableViewCell setSelected: animado: siempre ha animado = NO

Estoy tratando de hacer mi propia animation de selección. He creado una subclass de UITableViewCell. Hago mi animation de selección en -setSelected:animated: method. Funciona según lo previsto al seleccionar o anular la selección de las celdas tocándolos. El problema es que la animation también se ve durante el desplazamiento, ya que -setSelected:animated: se -setSelected:animated: en cada celda antes de que aparezca. Así es como funciona el mecanismo de reutilización de células, lo entiendo. Lo que no consigo es que siempre llama a este método con animation = NO, ni con toque ni en desplazamiento. Esto me parece un error lógico. Supuse que se suponía que debía seleccionar celdas con animation cuando las toque y sin animation cuando aparece la celda reutilizada. ¿El parámetro animated se usa alguna vez en cualquier lugar, excepto las llamadas manuales? Aquí está mi código:

 - (void)setSelected:(BOOL)selected animated:(BOOL)animated { BOOL alreadySelected = (self.isSelected) && (selected); BOOL alreadyDeselected = (!self.isSelected) && (!selected); [super setSelected:selected animated:animated]; if ((alreadySelected) || (alreadyDeselected)) return; NSLog(@"Animated selection: %@", animated ? @"YES" : @"NO"); NSTimeInterval duration; if (animated) { duration = 0.25; } else { duration = 0.0; } [CATransaction begin]; [CATransaction setAnimationDuration:duration]; if (selected) { //layer properties are changed here... } else { //layer properties are changed here... } [CATransaction commit]; } 

Esto siempre se queda sin la animation. No puedo pensar en ninguna otra forma tan fácil de manejar la selección personalizada. La implementación de los methods -didSelectRow en el controller parece ser mucho peor y no se llama durante el desplazamiento, por lo que las celdas reutilizadas aparecerán en un estado incorrecto. ¿Algúna idea de cómo arreglar esto?

ACTUALIZAR:

Encontré una solución temporal:

 #pragma mark - Table View Delegate - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; [cell setSelected:YES animated:YES]; return indexPath; } - (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; [cell setSelected:NO animated:YES]; return indexPath; } 

Funciona, pero no me gusta. El hecho de que el delegado de TableView tenga que saber algo acerca de la selección y no está todo contenido en un lugar me fastidia mucho. Y -setSelected se llama dos veces al grabar una fila, con y sin animation.

Así es como las vistas de tabla fueron diseñadas para funcionar. Cuando lo selecciona, se resalta de inmediato, por lo que no se necesita animation. Sin embargo, usted (debería, de todos modos) ver la celda de vista de tabla anular la selección con animation cuando vuelve a la vista de tabla. Puede ver que al usar este código en el -viewWillAppear:override:

 [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated] 

Eso sucederá automáticamente si está utilizando un UITableViewController y tiene su propiedad clearsSelectionOnViewWillAppear en YES .

Si desea un comportamiento diferente, debe codificarlo usted mismo. Si el código que ha publicado aquí funciona a su gusto, guárdelo. También puede modificar la subclass de celda para pasar -setSelected:animated: a la superclass en la -setSelected:animated: method override.

Aunque lleguemos tarde a la discusión, aquí hay un simple tweak para agregar en su código de celular:

 override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesEnded(touches, with: event) // Whatever you need to do here DispatchQueue.main.asyncAfter(deadline: .now() + 100.milliseconds) { self.setSelected(false, animated: true) } } 

Usar touchesEnded lugar de setSelected hace el truco, ya sea en el iPad o el iPhone.

Encontré una pequeña solución con el método prepareForReuse que se invoca cada vez que se reutiliza la célula:

 class MyTableViewCell: UITableViewCell { private var shouldAnimate = false override init(style: UITableViewCellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none } requinetworking init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func prepareForReuse() { shouldAnimate = false } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) if shouldAnimate { //your animation } else { shouldAnimate = true } } 

Espero eso ayude.