tutorial source example data collection ios uicollectionview

ios - source - UICollectionView: Anima el cambio de tamaño de celda en la selección



uicollectionview swift 4 tutorial (8)

Animar el tamaño de una celda funciona de la misma manera para las vistas de colección que para las vistas de tabla. Si desea animar el tamaño de una celda, tenga un modelo de datos que refleje el estado de la celda (en mi caso, solo uso una bandera (CollectionViewCellExpanded, CollectionViewCellCollapsed) y devuelvo un CGSize en consecuencia.

Cuando llame y vacíe la llamada performBathUpdates, la vista se anima automáticamente.

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [collectionView performBatchUpdates:^{ // append your data model to return a larger size for // cell at this index path } completion:^(BOOL finished) { }]; }

Lo que quiero hacer es cambiar el tamaño de UICollectionViewCell y animar ese cambio cuando se selecciona la celda. Ya logré hacer eso sin anunciar marcando una celda como se seleccionó en collectionView: didSelectItemAtIndexPath: y luego reloadData a reloadData en mi UICollectionView, mostrando la celda seleccionada con un tamaño diferente.

Sin embargo, esto sucede todo a la vez, y no tengo ni idea de cómo hacer ese cambio de tamaño animado. ¿Algunas ideas?

Ya encontré las células de Animate uicollectionview en la selección , pero la respuesta fue inespecífica para mí y aún no me di cuenta si también podría ayudarme en mi caso.


Con la ayuda de Chase Roberts, encontré la solución a mi problema. Mi código básicamente se ve así:

// Prepare for animation [self.collectionView.collectionViewLayout invalidateLayout]; UICollectionViewCell *__weak cell = [self.collectionView cellForItemAtIndexPath:indexPath]; // Avoid retain cycles void (^animateChangeWidth)() = ^() { CGRect frame = cell.frame; frame.size = cell.intrinsicContentSize; cell.frame = frame; }; // Animate [UIView transitionWithView:cellToChangeSize duration:0.1f options: UIViewAnimationOptionCurveLinear animations:animateChangeWidth completion:nil];

Para una explicación más detallada:

  1. Uno de los pasos más importantes es la llamada invalidateLayout en UICollectionView.collectionViewLayout que está utilizando. Si lo olvida, es probable que las células crezcan más allá de los límites de su colección; es algo que probablemente no desee que suceda. Además, considere que su código debería presentar en algún momento el nuevo tamaño de su celda para su diseño. En mi caso (estoy usando un UICollectionViewFlowLayout ), collectionView:layout:sizeForItemAtIndexPath método collectionView:layout:sizeForItemAtIndexPath para reflejar el nuevo tamaño de la celda modificada. Olvidando esa parte, nada sucederá con el tamaño de tu celda si primero llamas a invalidateLayout y luego tratas de animar el cambio de tamaño.

  2. Lo más extraño (al menos para mí) pero importante es que llamas a invalidateLayout no dentro del bloque de animación. Si lo haces, la animación no se mostrará suave, sino que parpadeará y parpadeará.

  3. UIView llamar al UIView transitionWithView:duration:options:animations:completion: UIView con la celda como argumento para transitionWithView , no toda la vista de la colección, porque es la celda que desea animar, no toda la colección.

  4. Utilicé el método intrinsicContentSize de mi celda para devolver el tamaño que deseo; en mi caso, hago crecer y reducir el ancho de la celda para mostrar un botón u ocultarlo, dependiendo del estado de selección de la celda.

Espero que esto ayude a algunas personas. Para mí, me tomó varias horas descubrir cómo hacer que la animación funcione correctamente, así que trato de liberar a otros de esa carga que consume tiempo.


El uso de performBatchUpdates no animará el diseño del contenido de la celda. En cambio, puede usar lo siguiente:

collectionView.collectionViewLayout.invalidateLayout() UIView.animate( withDuration: 0.4, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: UIViewAnimationOptions(), animations: { self.collectionView.layoutIfNeeded() }, completion: nil )

Esto da una animación muy suave.

Esto es similar a la respuesta de Ignatius Tremor, pero la animación de transición no funcionó correctamente para mí.

Consulte https://github.com/cnoon/CollectionViewAnimations para obtener una solución completa.


Esta es la solución más simple que he encontrado, funciona como un encanto. Suave animación, y no estropea el diseño.

Rápido

collectionView.performBatchUpdates({}){}

Obj-C

[collectionView performBatchUpdates:^{ } completion:^(BOOL finished) { }];

¡Los bloques (cierres en Swift) se deben dejar vacíos intencionalmente!


Esto funcionó para mí.

collectionView.performBatchUpdates({ () -> Void in let ctx = UICollectionViewFlowLayoutInvalidationContext() ctx.invalidateFlowLayoutDelegateMetrics = true self.collectionView!.collectionViewLayout.invalidateLayoutWithContext(ctx) }) { (_: Bool) -> Void in }


He tenido éxito animando cambios usando -setCollectionViewLayout:animated: para crear una nueva instancia del mismo diseño de vista de colección.

Por ejemplo, si está utilizando un UICollectionViewFlowLayout , entonces:

// Make sure that your datasource/delegate are up-to-date first // Then animate the layout changes [collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];


Una buena forma de animar el tamaño de la celda es sobrescribir isSelected en la collectionViewCell.

class CollectionViewCell: UICollectionViewCell { override var isHighlighted: Bool { didSet { if isHighlighted { UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseOut, animations: { self.transform = CGAffineTransform(scaleX: 0.95, y: 0.95) }, completion: nil) } else { UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseOut, animations: { self.transform = CGAffineTransform(scaleX: 1, y: 1) }, completion: nil) } } } }


[UIView transitionWithView:collectionView duration:.5 options:UIViewAnimationOptionTransitionCurlUp animations:^{ //any animatable attribute here. cell.frame = CGRectMake(3, 14, 100, 100); } completion:^(BOOL finished) { //whatever you want to do upon completion }];

Juega un poco con esas líneas dentro de tu método didselectItemAtIndexPath.