2012-12-12 8 views
28

Ich habe einige Daten, die in einem anderen Thread abgerufen werden, der den Header einer UICollectionView aktualisiert. Ich habe jedoch keine effiziente Möglichkeit gefunden, eine zusätzliche Ansicht, z. B. eine Kopf- oder Fußzeile, neu zu laden.Reload UICollectionView Kopf- oder Fußzeile?

Ich kann collectionView reloadSections: anrufen, aber dies lädt den gesamten Abschnitt, der nicht notwendig ist. collectionView reloadItemsAtIndexPaths: scheint nur auf Zellen zu zielen (keine zusätzlichen Ansichten). Und das Anrufen von setNeedsDisplay auf der Kopfzeile scheint nicht zu funktionieren. Fehle ich etwas?

Antwort

2

Hier sind zwei Möglichkeiten, wie Sie es tun könnten.

1. Erstellen Sie ein veränderbares Modell, um die möglicherweise verfügbaren Daten zu sichern. Verwenden Sie KVO in der geerbten Klasse von UICollectionReusableView, um die Änderungen zu beobachten und die Headeransicht mit den neuen Daten zu aktualisieren, sobald sie verfügbar sind.

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

dann Listener-Methode in Kopfansicht

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

2. Benachrichtigungs-Listener zu der Ansicht Additions- und eine Benachrichtigung hinterlassen, wenn die Daten erfolgreich zur Verfügung gekommen sind. Nachteil ist, dass dies eine breite Anwendung und kein sauberes Design ist.

// 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

Ich habe nicht verwendet KVO, aber ich habe für Aktualisierungen der Daten, stellen Sie die Felder auf meiner benutzerdefinierten Header-Klasse und rief setNeedsDisplay auf sie zugehört, aber nichts geändert . Ich habe mehr Probleme damit, den Header zu aktualisieren, als ich mit der Architektur bin, wie ich ihn aktualisiere. – akaru

+0

Haben Sie versucht, invalidateLayout aufzurufen. Aktualisiert das Ihre Kopfzeile? – Samuel

+0

das hat auch nicht funktioniert. – akaru

11

Ich lief in das gleiche Problem, und ich beendete die Ansicht mit seiner Tag-Nachschlagen auf ein Etikett bearbeiten:

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

Wie du es einen ganzen Abschnitt zu laden unnötig sagte, was jede Animation auf Zellen aufhebt. Meine Lösung ist nicht ideal, aber es ist einfach genug.

+0

Ich fürchte, dies würde die Wiederverwendung von Headern verhindern oder Speicherprobleme verursachen. – akaru

+3

@akaru es funktioniert gut für mich. Nicht sicher, warum es Speicherprobleme geben würde, da es nur ein Tag ist. –

+2

Schlechteste Antwort neben KVO – TheCodingArt

3

Ich habe das gleiche Problem. Ich habe versucht @ BobVorks Antwort und es funktioniert gut, wenn nur die Zelle wiederverwendet wurde, sonst wird es nicht. Also habe ich versucht, einen saubereren Weg zu finden, um dies zu erreichen, und ich kam nach dem performBatchUpdate (Completion-Block) die ganze UICollectionView neu zu laden und es funktioniert gut. Er lädt die Collection ohne Abbruch der Animation im insertItemsAtIndexPath erneut. Eigentlich habe ich persönlich die letzten 2 Antworten gewählt, weil ich finde, dass es funktioniert, aber in meinem Fall ist dies der sauberste Weg, es zu tun. auch

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

können Sie verwenden

[[_collectionView collectionViewLayout] invalidateLayout] 
+3

sollte dies wirklich die angenommene Antwort sein – tropicalfish

+1

perfekte Antwort ..! –

+1

Das lädt das gesamte Layout neu. Unabhängig von zusätzlichen Ansichten oder nicht. – TheCodingArt

1

Hier ist, was ich nur die Abschnittsüberschriften zu aktualisieren haben, die zur Zeit in den Speicher geladen werden:

  • hinzufügen weakToStrong NSMapTable. Wenn Sie eine Kopfzeile erstellen, fügen Sie die Kopfzeile als schwach gehaltenen Schlüssel mit dem Objekt indexPath hinzu. Wenn wir den Header wiederverwenden, aktualisieren wir den indexPath.
  • Wenn Sie die Kopfzeilen aktualisieren müssen, können Sie die Objekte/Schlüssel von NSMapTable nach Bedarf auflisten.

    @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

Diese Frage ist sehr alt, aber eine einfache Möglichkeit, es zu tun ist, um nur eine Verzögerung einstellen, die die Zeit deckt Ihre Ansicht animiert und Deaktivieren der Animation, während Sie die Ansicht aktualisieren ... in der Regel ein Lösch oder Einfügen dauert ungefähr.35 Sekunden so einfach tun:

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]; 
}];