ios6 - Recargar UICollectionView encabezado o pie de página?
(8)
Aquí hay dos maneras en que podría hacerlo.
1. Cree un modelo mutable para respaldar los datos que eventualmente estarán disponibles. Use KVO en la clase heredada de UICollectionReusableView para observar los cambios y actualizar la vista del encabezado con los nuevos datos a medida que estén disponibles.
[model addObserver:headerView
forKeyPath:@"path_To_Header_Data_I_care_about"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
luego implementar el método de escucha en la vista de cabecera
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
2. agregue el servicio de escucha de notificaciones a la vista y publique una notificación cuando los datos estén disponibles con éxito. El inconveniente es que se trata de una aplicación amplia y no de un diseño limpio.
// place in shared header file
#define HEADER_DATA_AVAILABLE @"Header Data Available Notification Name"
// object can contain userData property which could hole data needed.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(headerDataAvailable:) name:HEADER_DATA_AVAILABLE object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:HEADER_DATA_AVAILABLE object:nil];
Tengo algunos datos que se obtienen en otro hilo que actualiza el encabezado de UICollectionView. Sin embargo, no he encontrado una forma eficiente de volver a cargar una vista complementaria, como un encabezado o pie de página.
Puedo llamar a collectionView reloadSections:
pero esto vuelve a cargar toda la sección, lo cual es innecesario. collectionView reloadItemsAtIndexPaths:
solo parece apuntar a las celdas (no a vistas complementarias). Y llamar a setNeedsDisplay
en el encabezado en sí tampoco parece funcionar. ¿Me estoy perdiendo de algo?
Esta pregunta es muy antigua, pero una forma simple de hacerlo es simplemente establecer un retraso que cubra el tiempo que su vista está animando y deshabilitando la animación mientras actualiza la vista ... por lo general, una eliminación o inserción lleva aproximadamente .35 segundos, así que simplemente hacer:
delay(0.35){
UIView.performWithoutAnimation{
self.collectionView.reloadSections(NSIndexSet(index: 1))
}
Esto es lo que hice para actualizar solo los encabezados de sección que actualmente están cargados en la memoria:
- Añadir un NSMapTable
NSMapTable
. Cuando cree un encabezado, agregue el encabezado como la clave débilmente mantenida, con el objeto indexPath. Si reutilizamos el encabezado, actualizaremos indexPath. - Cuando necesite actualizar los encabezados, ahora puede enumerar los objetos / claves de
NSMapTable
según sea necesario.
@interface YourCVController ()
@property (nonatomic, strong) NSMapTable *sectionHeaders;
@end
@implementation YourCVContoller
- (void)viewDidLoad {
[super viewDidLoad];
// This will weakly hold on to the KEYS and strongly hold on to the OBJECTS
// keys == HeaderView, object == indexPath
self.sectionHeaders = [NSMapTable weakToStrongObjectsMapTable];
}
// Creating a Header. Shove it into our map so we can update on the fly
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
PresentationSectionHeader *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"presentationHeader" forIndexPath:indexPath];
// Shove data into header here
...
// Use header as our weak key. If it goes away we don''t care about it
// Set indexPath as object so we can easily find our indexPath if we need it
[self.sectionHeaders setObject:indexPath forKey:header];
return header;
}
// Update Received, need to update our headers
- (void) updateHeaders {
NSEnumerator *enumerator = self.sectionHeaders.keyEnumerator;
PresentationSectionHeader *header = nil;
while ((header = enumerator.nextObject)) {
// Update the header as needed here
NSIndexPath *indexPath = [self.sectionHeaders objectForKey:header];
}
}
@end
Me encontré con el mismo problema y terminé buscando la vista usando su etiqueta para editar una etiqueta:
UICollectionReusableView *footer = (UICollectionReusableView*)[self.collectionView viewWithTag:999];
UILabel *footerLabel = (UILabel*)[footer viewWithTag:100];
Como usted dijo, no es necesario volver a cargar una sección completa, que cancela también cualquier animación en las celdas. Mi solución no es ideal, pero es bastante fácil.
También puedes usar
[[_collectionView collectionViewLayout] invalidateLayout]
Tengo el mismo problema. Intenté la respuesta de @BobVorks y está funcionando bien, si solo la celda se reutilizara, de lo contrario no funcionará. Entonces, traté de encontrar una forma más limpia de lograr esto y encontré recargando todo el UICollectionView después del performBatchUpdate (bloque de finalización) y está funcionando muy bien. Recarga la Colección Sin ninguna cancelación de animación en el insertItemsAtIndexPath. En realidad, personalmente he votado 2 respuestas recientes porque lo encuentro funcionando pero en mi caso, esta es la forma más limpia de hacerlo.
[self.collectionView performBatchUpdates:^{
// perform indexpaths insertion
} completion:^(BOOL finished) {
[self.collectionView reloadData];
}];
Versión Swift 3/4 :
collectionView.collectionViewLayout.invalidateLayout()
¡Precaución!
Si cambia el número de elementos de collectionView
al mismo tiempo (por ejemplo, muestra el pie de página solo si se cargaron todas las celdas), se bloqueará . Primero debe volver a cargar los datos para asegurarse de que el número de elementos sea el mismo antes y después de invalidateLayout()
:
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
[UIView performWithoutAnimation:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:4]];
}];
[UIView performWithoutAnimation:^{
[self.collectionView reloadData];
}];