Animación de UITableViewCell dibujada a medida al ingresar al modo de edición

Fondo

En primer lugar, mucha gratitud a atebits por su muy informativo blog Post Fast Scrolling en Tweetie con UITableView . La publicación explica en detalle cómo los desarrolladores pudieron exprimir tanto performance de desplazamiento como sea posible fuera de UITableViews en Tweetie .

Metas

A partir del código fuente vinculado desde la publicación del blog ( original ) ( mi github repo ):

  1. Permita que UITableView use estas celdas personalizadas para cambiar al modo de edición, exponiendo la interfaz de usuario para eliminar un elemento de la tabla. ( github commit )

  2. Mueva el text de la celda a un lado mientras el control de eliminación se desliza por la izquierda. Esto está completo, aunque el text salta hacia adelante y hacia atrás sin animation. ( github commit )

  3. Aplique animation al movimiento de text en el objective 2 anterior para una experiencia de usuario sin problemas. Este es el paso donde me quedé atrapado.

La pregunta

¿Cuál es la mejor manera de presentar esta animation para completar el objective 3? Sería bueno si esto se puede hacer de una manera que mantiene la lógica de mi último compromiso porque me encantaría la opción de mover solo la parte conflictiva de la vista, mientras que las partes no conflictivas (como el text justificado a la derecha) permanezca en el mismo lugar o mueva una cantidad diferente de píxeles. Si lo anterior no es posible, deshacer mi último compromiso y replacelo con una opción que deslice la vista completa a la derecha sería una solución viable también.

Aprecio cualquier ayuda que cualquier persona pueda proporcionar, desde sugerencias rápidas e ideas hasta fragments de código o confirmaciones de github. Por supuesto que puedes dar un bocado a mi repository si quieres. Me mantendré involucrado con esta pregunta para asegurarme de que cualquier resolución exitosa se haya comprometido con github y se haya documentado completamente aquí. ¡Muchas gracias por tu time!

Pensamientos actualizados

He estado pensando mucho en esto desde mi primera publicación y me di count de que mover algunos elementos de text en relación con otros en la vista podría deshacer algunos de los objectives de performance originales resueltos en la publicación original del blog. Entonces, en este punto, estoy pensando en una solución donde toda la subvista individual esté animada a que su nueva position sea la mejor.

En segundo lugar, si se hace de esta manera, puede haber una instancia donde la subvista tenga un background personalizado de color o degradado. Es de esperar que esto se pueda hacer de forma que, en su position normal, el background se extienda sin ser visto a la izquierda lo suficiente para que cuando la vista se deslice hacia la derecha, el background personalizado siga visible a través de toda la celda.

Gracias a la respuesta de Craig que me indicó en la dirección correcta, tengo una solución para esto. Revertí mi confirmación que movió la position del text en function del modo de edición y la reemplazó con una nueva solución que establece la vista de contenido completa en la position correcta cada vez que se llama a la vista de layoutSubviews, lo que da como resultado una animation automática al cambiar al modo de edición :

- (void)layoutSubviews { CGRect b = [self bounds]; b.size.height -= 1; // leave room for the separator line b.size.width += 30; // allow extra width to slide for editing b.origin.x -= (self.editing) ? 0 : 30; // start 30px left unless editing [contentView setFrame:b]; [super layoutSubviews]; } 

Al hacerlo así, pude eliminar el setFrame: override encontrado en ABTableViewCell.m porque su lógica anterior más mis adiciones ahora se encuentran en layoutSubviews.

Puse un background gris claro en las celdas para verificar que un background personalizado funcione correctamente sin permitirnos ver detrás de él a medida que avanza y parece funcionar de maravilla.

Gracias de nuevo a Craig y a cualquier otra persona que haya investigado esto.

GitHub se compromete con esta solución: ( enlace )

¿Cómo estás moviendo el text actualmente? ¿O más específicamente, en qué método UITableViewCell estás realizando el movimiento?

Según mi experiencia, anular el método layoutSubviews y configurar el marco aquí se envolverá automáticamente en una animation.

P.ej:

 - (void)layoutSubviews { if (self.editing) { [titleLabel setFrame:CGRectMake(62, 6, 170, 24)]; } else { [titleLabel setFrame:CGRectMake(30, 6, 200, 24)]; } [super layoutSubviews]; } 

Para controlar completamente la edición en su celda personalizada, debe anular el método willTransitionToState en su subclass UITableViewCell y verificar la máscara de estado

 - (void)willTransitionToState:(UITableViewCellStateMask)state { NSString *logStr = @"Invoked"; if ((state & UITableViewCellStateShowingEditControlMask) != 0) { // you need to move the controls in left logStr = [NSString stringWithFormat:@"%@ %@",logStr,@"UITableViewCellStateShowingEditControlMask"]; } if ((state & UITableViewCellStateShowingDeleteConfirmationMask) != 0) { // you need to hide the controls for the delete button logStr = [NSString stringWithFormat:@"%@ %@",logStr,@"UITableViewCellStateShowingDeleteConfirmationMask"]; } NSLog(@"%@",logStr); [super willTransitionToState:state]; } 

También puedes anular layoutSubviews

 - (void)layoutSubviews { // default place for label CGRect alarmTimeRect = CGRectMake(37, 7, 75, 30); if (self.editing && !self.showingDeleteConfirmation) { // move rect in left alarmTimeRect = CGRectMake(77, 7, 75, 30); } [alarmTimeLabel setFrame:alarmTimeRect]; [super layoutSubviews]; } 

Para manejar el deslizar también: (self.editing &&! Self.showingDeleteConfirmation)

También tuve esta pregunta: ¿cómo animar un modo de edición personalizado? Realmente no me gustó la solución aquí, así que decidí pensar un poco y encontrar una solución diferente. No sé si es mejor, pero prefiero eso. Entonces decidí compartirlo aquí:

En la celda personalizada (henetworkingar de UITableViewCell), simplemente sobrecargue el setEditar:

 - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [super setEditing:editing animated:animated]; if (animated) { [UIView beginAnimations:@"setEditingAnimation" context:nil]; [UIView setAnimationDuration:0.3]; } if (editing) { /* do your offset and resize here */ } else { /* return to the original here*/ } if (animated) [UIView commitAnimations]; } 

No controlo si el valor de edición es el mismo, pero esa es solo una idea de cómo lo hice.

En realidad, hay cuatro estados editados.

UITableViewCellStateDefaultMask = 0

UITableViewCellStateShowingEditControlMask = 1 << 0 = 0b01 = 1 estableciendo tableView.edit = YES

UITableViewCellStateShowingDeleteConfirmationMask = 1 << 1 = 0b10 = 2 deslizando para eliminar

UITableViewCellStateShowingEditControlMask y UITableViewCellStateShowingDeleteConfirmationMask = (1 << 1) & (1 << 0) = 0b11 = 3 estableciendo tableView.edit = YES y presionando el button "detener"

Lo que me confundió es que cuando el estado 3 se transfiere al estado 1, no se llamará a ningún selector que no haga uso de self.showingDeleteConfirmation para cambiar el layout en iOS7. Por lo tanto, para aclarar entre el estado 2 y el estado 3, agregué una instancia variable para implementarlo. Funciona muy bien para mí.

 -(void)willTransitionToState:(UITableViewCellStateMask)state{ [super willTransitionToState:state]; //Custom delete button from //http://stackoverflow.com/questions/19159476/uitableviewcelldeleteconfirmationcontrol-issue if((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableViewCellStateShowingDeleteConfirmationMask){ [self recurseAndReplaceSubViewIfDeleteConfirmationControl:self.subviews]; [self performSelector:@selector(recurseAndReplaceSubViewIfDeleteConfirmationControl:) withObject:self.subviews afterDelay:0]; } _swipeDelete = NO; if(state==2){ //Swipe to delete confirm _swipeDelete = YES; } if(state==3){ //Edit state to delete confirm } } - (void)layoutSubviews{ [super layoutSubviews]; self.contentView.frame = CGRectMake(10, 5.0, 300, self.frame.size.height - 10); if(self.editing){ self.contentView.frame = CGRectMake(40, 5.0, 270, self.frame.size.height - 10); } if(_swipeDelete){ self.contentView.frame = CGRectMake(10, 5.0, 300, self.frame.size.height - 10); } }