2012-12-12 18 views
28

Ho alcuni dati che vengono recuperati in un altro thread che aggiorna l'intestazione di UICollectionView. Tuttavia, non ho trovato un modo efficiente per ricaricare una vista supplementare come un'intestazione o un piè di pagina.Ricarica l'intestazione o il piè di pagina di UICollectionView?

Posso chiamare collectionView reloadSections:, ma questo ricarica l'intera sezione che non è necessaria. collectionView reloadItemsAtIndexPaths: sembra solo target celle (non visualizzazioni supplementari). E chiamare setNeedsDisplay sull'intestazione non sembra funzionare. Mi sto perdendo qualcosa?

risposta

2

Ecco due modi per farlo.

1. Creare un modello mutabile per ripristinare i dati che saranno eventualmente disponibili. Utilizzare KVO nella classe ereditata di UICollectionReusableView per osservare le modifiche e aggiornare la vista dell'intestazione con i nuovi dati non appena disponibili.

[model addObserver:headerView 
     forKeyPath:@"path_To_Header_Data_I_care_about" 
      options:(NSKeyValueObservingOptionNew | 
        NSKeyValueObservingOptionOld) 
      context:NULL]; 

quindi implementare il metodo ascoltatore in vista di testa

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 

2. aggiungere ascoltatore notifica alla vista e inviare una notifica quando i dati è venuto con successo disponibili. Il rovescio della medaglia è che questa è un'applicazione ampia e non un design pulito.

// 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]; 
+0

non ho usato KVO, ma ho ascoltato per gli aggiornamenti dei dati, impostare i campi mia classe intestazione personalizzata, e chiamato setNeedsDisplay su di esso, ma non è cambiato nulla . Sto avendo problemi di più nell'ottenere l'intestazione per rinfrescarsi rispetto a me con l'architettura su come aggiornarlo. – akaru

+0

Hai provato a chiamare invalidateLayout. Aggiorna la tua intestazione? – Samuel

+0

che non ha funzionato neanche. – akaru

11

Ho appena incontrato lo stesso problema, e ho finito per guardare la vista utilizzando il tag per modificare un'etichetta:

UICollectionReusableView *footer = (UICollectionReusableView*)[self.collectionView viewWithTag:999]; 
UILabel *footerLabel = (UILabel*)[footer viewWithTag:100]; 

Come hai detto tu non è necessario ricaricare un'intera sezione, che annulla qualsiasi animazione anche sulle celle. La mia soluzione non è l'ideale, ma è abbastanza facile.

+0

Avrei paura di farlo inibire il riutilizzo dell'intestazione o causare problemi di memoria. – akaru

+3

@akaru funziona bene per me. Non sono sicuro del motivo per cui ci sarebbero problemi di memoria in quanto è solo un tag. –

+2

La peggiore risposta accanto a KVO – TheCodingArt

3

Ho avuto lo stesso problema. Ho provato la risposta di @ BobVorks e funziona bene, se solo la cella è stata riutilizzata altrimenti non lo farà. Così, ho provato a trovare un modo più pulito per raggiungere questo obiettivo e sono arrivato ricaricando l'intero UICollectionView dopo il performBatchUpdate (blocco di completamento) e funziona benissimo. Ricarica la raccolta senza alcuna cancellazione dell'animazione in insertItemsAtIndexPath. In realtà io personalmente ho votato 2 recenti risposte perché trovo che funzioni, ma nel mio caso, questo è il modo più pulito per farlo.

[self.collectionView performBatchUpdates:^{ 
    // perform indexpaths insertion 
} completion:^(BOOL finished) { 
    [self.collectionView reloadData]; 
}]; 
19

È inoltre possibile utilizzare

[[_collectionView collectionViewLayout] invalidateLayout] 
+3

questa dovrebbe essere la risposta accettata – tropicalfish

+1

risposta perfetta ..! –

+1

Ricarica l'intero layout. Indipendentemente dalle viste supplementari o no. – TheCodingArt

1

Ecco cosa ho fatto per aggiornare solo le intestazioni di sezione che sono attualmente caricati in memoria:

  • Aggiungi un weakToStrong NSMapTable. Quando si crea un'intestazione, aggiungere l'intestazione come chiave con tenuta debole, con l'oggetto indexPath. Se riutilizziamo l'intestazione, aggiorneremo indexPath.
  • Quando è necessario aggiornare le intestazioni, è ora possibile enumerare gli oggetti/chiavi da NSMapTable secondo necessità.

    @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 
1

Questa domanda è molto vecchio, ma un modo semplice per farlo è quello di impostare solo un ritardo che copre il tempo il vostro punto di vista è l'animazione e disabilitando l'animazione, mentre si aggiorna la vista ... di solito una cancellazione o inserire prende circa.35 secondi in modo basta fare:

delay(0.35){ 
      UIView.performWithoutAnimation{ 
      self.collectionView.reloadSections(NSIndexSet(index: 1)) 
      } 
0
[UIView performWithoutAnimation:^{ 
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:4]]; 
}]; 

[UIView performWithoutAnimation:^{ 
[self.collectionView reloadData]; 
}]; 
Problemi correlati