Animar una celda UICollectionView en la selección

Tengo una cuadrícula básica en UICollectionView . Es una simple columna de 2 columnas, layout de varias filas utilizando UICollectionViewDelegateFlowLayout . Cuando se selecciona una celda, quiero atenuar el background, flotar la celda en el centro de la pantalla y luego tener un flujo de trabajo basado en la celda seleccionada. Soy bastante nuevo en UICollectionViews , y no estoy seguro de la mejor manera de hacerlo.

¿Debo tener un layout personalizado de UICollectionView para cuando se selecciona una celda?

¿O hay una forma en que puedo animar la celda seleccionada sin tener que crear una nueva disposition

Si alguien puede hacerme avanzar en la dirección correcta, creo que seré bueno para investigar cómo ejecutarlo.

Después de probar varias (y bastante hacky) soluciones, solucioné esto escribiendo mi propio layout de UICollectionView . Soluciones anteriores que intenté:

  • Agregue una UIView personalizada que exceda el UICollectionView e intente falsificar la celda original moviéndola superpuesta, atenuando el background y animando la nueva UIView
  • Animar la celda sin crear una nueva distribución

Intentaba evitarlo, pero después de codificarlo, fue mucho less doloroso de lo que pensaba originalmente.

Aquí está mi código, para cualquier persona interesada:

.marido:

 @interface FMStackedLayout : UICollectionViewLayout @property(nonatomic,assign) CGPoint center; @property(nonatomic,assign) NSInteger cellCount; -(id)initWithSelectedCellIndexPath:(NSIndexPath *)indexPath; @end 

.metro:

 #define ITEM_WIDTH 128.0f #define ITEM_HEIGHT 180.0f static NSUInteger const RotationCount = 32; static NSUInteger const RotationStride = 3; static NSUInteger const PhotoCellBaseZIndex = 100; @interface FMStackedLayout () @property(strong,nonatomic) NSArray *rotations; @property(strong,nonatomic) NSIndexPath *selectedIndexPath; @end @implementation FMStackedLayout #pragma mark - Lifecycle -(id)initWithSelectedCellIndexPath:(NSIndexPath *)indexPath{ self = [super init]; if (self) { self.selectedIndexPath = indexPath; [self setup]; } return self; } -(id)initWithCoder:(NSCoder *)aDecoder{ self = [super init]; if (self){ [self setup]; } return self; } -(void)setup{ NSMutableArray *rotations = [NSMutableArray arrayWithCapacity:RotationCount]; CGFloat percentage = 0.0f; for (NSUInteger i = 0; i < RotationCount; i++) { // Ensure that each angle is different enough to be seen CGFloat newPercentage = 0.0f; do { newPercentage = ((CGFloat)(arc4random() % 220) - 110) * 0.0001f; } while (fabsf(percentage - newPercentage) < 0.006); percentage = newPercentage; CGFloat angle = 2 * M_PI * (1.0f + percentage); CATransform3D transform = CATransform3DMakeRotation(angle, 0.0f, 0.0f, 1.0f); [rotations addObject:[NSValue valueWithCATransform3D:transform]]; } self.rotations = rotations; } #pragma mark - Layout -(void)prepareLayout{ [super prepareLayout]; CGSize size = self.collectionView.frame.size; self.cellCount = [self.collectionView numberOfItemsInSection:0]; self.center = CGPointMake(size.width / 2.0, size.height / 2.0); } -(CGSize)collectionViewContentSize{ return self.collectionView.frame.size; } -(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; attributes.size = CGSizeMake(ITEM_WIDTH, ITEM_HEIGHT); attributes.center = self.center; if (indexPath.item == self.selectedIndexPath.item) { attributes.zIndex = 100; }else{ attributes.transform3D = [self transformForPersonViewAtIndex:indexPath]; } return attributes; } -(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ NSMutableArray *attributes = [NSMutableArray array]; for (NSInteger i = 0; i < self.cellCount; i++) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]]; } return attributes; } #pragma mark - Private -(CATransform3D)transformForPersonViewAtIndex:(NSIndexPath *)indexPath{ NSInteger offset = (indexPath.section * RotationStride + indexPath.item); return [self.rotations[offset % RotationCount] CATransform3DValue]; } @end 

Luego, en tu UICollectionView, llamas

 MyLayout *stackedLayout = [[MyLayout alloc] initWithSelectedCellIndexPath:indexPath]; [stackedLayout invalidateLayout]; [self.collectionView setCollectionViewLayout:stackedLayout animated:YES]; 

Las animaciones entre celdas serán manejadas por el layout personalizado.

Parece ser una pregunta de varias partes, así que responderé a una parte.

  1. UICollectionviewCells no se ajusta automáticamente al resaltar o seleccionar . Solo le dirá cuando la celda esté resaltada o seleccionada, con una exception:

En su mayor parte, la vista de colección modifica solo las properties de una celda para indicar que está seleccionada o resaltada; No cambia la apariencia visual de sus celdas, con una exception. Si la propiedad selectedBackgroundView una celda contiene una vista válida, la vista de colección muestra esa vista cuando la celda está resaltada o seleccionada.

De lo contrario, debe hacer el resaltado visual de forma manual. Por lo general, ajustando la propiedad .alpha de toda la celda o intercambiando la propiedad .image de un background UIImageView en la celda usando uno o más de los siguientes methods, a los que se puede acceder en el <UICollectionViewDelegate> :

 collectionView:didDeselectItemAtIndexPath: collectionView:didHighlightItemAtIndexPath: collectionView:didSelectItemAtIndexPath: collectionView:didUnhighlightItemAtIndexPath: collectionView:shouldDeselectItemAtIndexPath: collectionView:shouldHighlightItemAtIndexPath: collectionView:shouldSelectItemAtIndexPath: 

En cuanto al rest de su pregunta, me gustaría poder ser de más ayuda, pero no soy tan hábil con la animation de vista personalizada.