6

Ich versuche, die beste Methode zur Verarbeitung der Statuswiederherstellung für eine UICollectionView zu finden, deren Elemente sich möglicherweise verschieben. Mein Ziel ist es, sicherzustellen, dass das zuletzt angezeigte Element in der Sammlungsansicht immer noch sichtbar ist, wenn die App neu gestartet wird, auch wenn die Elemente verschoben wurden. Zum Beispiel befindet sich Element A in Zelle bei Index 3, wenn die App beendet wurde. Wenn die App neu startet, wenn das Modell angibt, dass Element A bei Index 4 angezeigt werden soll, soll die Auflistungsansicht den Offset zur Zelle am Index initialisieren 4.UICollectionView-Statuswiederherstellung: Anpassen der Bildlaufposition

ich dachte, dass das UIDataSourceModelAssociation Protokoll in meiner UICollectionViewDataSource Klasse Umsetzung kümmern würde dies für mich, wie die documentation Staaten:

[UITableView und UICollectionView] Klassen verwenden, die Methoden dieses Protokolls zu gewährleisten, dass dieselben Datenobjekte (und nicht nur die gleichen Zeilenindizes) in die Ansicht gescrollt und ausgewählt werden.

Doch was ich beobachtet habe, ist, dass dieses Protokoll implementiert richtig die indexPath der ausgewählten Zellen nicht beeinträchtigt während der Wiederherstellung (was meinen App nicht wichtig ist), aber es hat keinen Einfluss auf die Bildlaufposition. Die Bildlaufposition (contentOffset der Sammlungsansicht) wird immer genau dort wiederhergestellt, wo sie war, als die App beendet wurde, und nicht von der UICollectionViewDataSource.

Ich habe einen Workaround, der so aussieht. Es ist im Grunde das gleiche Muster wie das Modell assocation Protokoll, aber ich habe es zu tun manuell:

override func encodeRestorableStateWithCoder(coder: NSCoder) { 
    let identifier = determineIdOfCurrentlyVisibleCell() 
    coder.encodeObject(identifier, forKey: "visibleCellIdentifier") 
} 

override func decodeRestorableStateWithCoder(coder: NSCoder) { 
    if let identifier = coder.decodeObjectForKey("visibleCellIdentifier") as? String { 
     if let indexPath = model.indexPathForIdentifier(identifier) { 
      collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .CenteredVertically, animated: false) 
     } 
    } 
} 

Haben falsch verstehen ich die Verwendung von UIDataSourceModelAssociation? Gibt es einen Fehler? Gibt es einen eleganteren oder korrektiveren Weg, dies zum Laufen zu bringen?

+0

Wie ich 'indexPathForElementWithModelIdentifier sehen' entwickelt, um die gleiche Sache zu tun. Es klappt? – orkenstein

+0

@orkenstein Ich habe es versucht, aber es hat nicht funktioniert. Siehe mein OP: "Die Implementierung dieses Protokolls beeinflusst den IndexPfad der ausgewählten Zellen während der Wiederherstellung (was für meine App nicht wichtig ist), hat aber keinen Einfluss auf die Scroll-Position." –

Antwort

5

Wie bereits erwähnt, scheint UIDataSourceModelAssociation nicht mit der Wiederherstellung eines sichtbaren UICollectionView Offset zu arbeiten, sondern nur für ausgewählte Objekte. Ich habe versucht, Haltepunkte auf beiden modelIdentifierForElementAtIndexPath und indexPathForElementWithModelIdentifier setzen und bemerkte, dass sie nur nach der Auswahl einer Zelle aufgerufen wurden. Wenn ich die ausgewählten Zellen meiner Sammlungsansicht löschte, bevor ich meine App Hintergrundbilder erstellte, wurde modelIdentifierForElementAtIndexPath nicht aufgerufen, aber es würde einmal ich mindestens eine Zelle als ausgewählt festlegen. Zumindest kann ich bestätigen, dass Sie nicht die Einzige sind, die dieses Verhalten sieht.

Ich denke, wegen der unterschiedlichen Natur von ist es wahrscheinlich nicht einfach, Verhalten zu erstellen, das sichtbare Zellen zum richtigen Punkt scrollt, aber das ist offensichtlich nicht in Apples Dokumentation widerspiegelt. Das manuelle Codieren eines Bezeichners für die erste sichtbare Zelle für Ihr Layout sollte eine gute Alternative sein. Was ich tue, ist die Rolle in einem NSValue Offset Sammlung Ansicht Einwickeln und dass die Wiederherstellung: INview:

var collectionView: UICollectionView? 

// ... 

override func encodeRestorableStateWithCoder(coder: NSCoder) { 
    if let view = collectionView, offsetValue = NSValue(CGPoint: view.contentOffset) { 
     coder.encodeObject(offsetValue, forKey: CollectionViewContentOffsetKey) 
    } 

    super.encodeRestorableStateWithCoder(coder) 
} 

override func decodeRestorableStateWithCoder(coder: NSCoder) { 
    if let offsetValue = coder.decodeObjectForKey(CollectionViewContentOffsetKey) as? NSValue { 
     collectionView?.setContentOffset(offsetValue.CGPointValue(), animated: false) 
    } 

    super.decodeRestorableStateWithCoder(coder) 
} 
+1

Gute Analyse. Für mich ergibt das Sinn. –

+0

Das funktionierte, aber stellte den Offset an einer falschen Stelle wieder her - mit NavigationBar-Berechnungen stimmt etwas nicht. – soprof