Estoy usando UICollectionReusableView como encabezado de la sección UICollectionView . Habilité "encabezados fijos" con:
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout layout?.sectionHeadersPinToVisibleBounds = trueEstoy insertando nuevas secciones a la colección con:
collectionView.performBatchUpdates({ self.collectionView.insertSections(IndexSet(integersIn: collectionView.numberOfSections...viewModel.numberOfSections - 1)) }, completion: nil)Si la inserción ocurre cuando la colección se desplaza demasiado (el rebote está habilitado), el encabezado desaparecerá por un tiempo (vea el GIF a continuación). ¿Cómo puedo evitar este comportamiento?
Estoy usando iOS 12.1.4, pero también ocurre el mismo problema en los simuladores de iOS 11.x y 12.x.
El problema no ocurre si el efecto de rebote está desactivado, pero quiero mantenerlo activado para una sensación de desplazamiento más suave. Intenté invalidar el diseño antes/después de la actualización sin resultado. Gracias por los consejos.
EDITAR (26/02/2019)
Solución alternativa: envolver la inserción para performWithoutAnimation bloque de ejecución sin animación, resolver la desaparición del encabezado pero, obviamente, deshabilitar la animación de recarga.
UIView.performWithoutAnimation { collectionView.performBatchUpdates({ self.collectionView.insertSections(IndexSet(integersIn: collectionView.numberOfSections...viewModel.numberOfSections - 1)) }, completion: nil) }Desafortunadamente, al llamar a performBatchUpdates, el diseño anima automáticamente todos los elementos. Incluso hasta ahora, no hay forma de decir explícitamente qué elementos animar y cuáles no.
Sin embargo, se me ocurrió una resolución que es una especie de antipatrón.
Para su clase de encabezado, anule estos métodos:
-(void)setBounds:(CGRect)bounds { [CATransaction begin]; [CATransaction setDisableActions:self.shouldDisableAnimations]; [super setBounds:bounds]; [CATransaction commit]; } //-(void)setCenter:(CGPoint)center - (void)setCenter:(CGPoint)center { [CATransaction begin]; [CATransaction setDisableActions:self.shouldDisableAnimations]; [super setCenter:center]; [CATransaction commit]; }Ahora, si shouldDisableAnimations es verdadero, las animaciones automáticas de collectionView no se aplicarán a nuestro encabezado.
Sin embargo, deshabilitar las animaciones para el encabezado puede causar otras fallas (por ejemplo, cuando se desplaza mucho hacia abajo y luego elimina todas las celdas, el encabezado saltará a la parte superior instantáneamente y la vista de colección se desplazará hacia arriba con una animación que resultará en una falla).
Para manejar esto, debemos configurar shouldDisableAnimations para el encabezado en el momento correcto, que es cuando se llama a prepareForCollectionViewUpdates. Desafortunadamente, no podemos hacer esto a través del atributo del encabezado ya que los atributos se aplican al encabezado después de que finaliza la animación. Por lo tanto, debemos acceder directamente a la instancia del encabezado directamente desde el método prepareForCollectionViewUpdates. (Hay varias formas de hacer esto. Lo hice manteniendo una referencia débil del encabezado en una propiedad de clase de sí mismo)
-(void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems { // Keep track of insert and delete index paths [super prepareForCollectionViewUpdates:updateItems]; [self.indexPaths2Delete removeAllObjects]; [self.indexPaths2Insert removeAllObjects]; for (UICollectionViewUpdateItem *update in updateItems) { if (update.updateAction == UICollectionUpdateActionDelete) { [self.indexPaths2Delete addObject:update.indexPathBeforeUpdate]; } else if (update.updateAction == UICollectionUpdateActionInsert) { [self.indexPaths2Insert addObject:update.indexPathAfterUpdate]; } } if (self.indexPaths2Insert.count > 0 || self.indexPaths2Delete.count > 0) { HomeHeaderView.liveInstance.shouldDisableAnimations = false; //since it may cause scrolling, we should enable the animations } else HomeHeaderView.liveInstance.shouldDisableAnimations = true; //there's nothing added or deleted, so keep the header sticked. }La solución anterior que proporcioné anteriormente parece no funcionar en iOS 13.
Durante performBatchUpdates, UICollectionView no aplica atributos de diseño para los elementos. La única forma de solucionar esto es configurar el marco (o cualquier otro parámetro) en el encabezado explícitamente desde el método prepare() del diseño. Debido a que se está realizando una animación en curso, UICollectionView no se distribuirá durante la animación.
Creo que Apple tiene que agregar una función para marcar explícitamente qué elementos participan en la animación y cuáles no. Esto se puede hacer a través de los atributos de diseño de los elementos o un método separado en UICollectionViewLayout.
¡Acceder a las instancias de elementos desde el diseño es un no-no! Pero no hay otras soluciones en este momento.
También estaba teniendo el mismo problema, pero el trabajo que he hecho es volver a cargar el collectionView (el encabezado fijo no desapareció) en lugar de insertarlo.