Restore UICollectionView state: adjust scroll position

I am trying to find a better way to handle state recovery for a UICollectionView whose elements can be moved. My goal is to make sure that the last viewed item in the collection view is still displayed when the application restarts, even if the items are moved. For example, element A is in the cell with index 3, when the application was killed, and when the application restarts, if the model reports that element A should be displayed with index 4, I want the collection view to initialize the offset of the cell with index 4.

I thought that implementing the UIDataSourceModelAssociation protocol in my UICollectionViewDataSource class UICollectionViewDataSource take care of this for me, as the documentation says:

In the classes

[UITableView and UICollectionView] use the methods of this protocol to ensure that the same data objects (and not just the same row indices) are scrolled into the view and selected.

However, I noticed that the implementation of this protocol correctly affects the indexPath of selected cells during recovery (which is not important for my application), but this does not affect the scroll position. The scroll position (contentOffset of the collection view) is always restored exactly where it was when the application was killed and not affected by the UICollectionViewDataSource.

I have a workaround that looks like this. This is basically the same template as the model matching protocol, but I have to do it manually:

 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) } } } 

I misunderstood the use of UIDataSourceModelAssociation? Is there a mistake? Is there a more elegant or proper way to make this work?

+6
source share
1 answer

As already stated, UIDataSourceModelAssociation does not seem to work with restoring the visible offset of the UICollectionView , but only for selected items. I tried to set breakpoints on both modelIdentifierForElementAtIndexPath and indexPathForElementWithModelIdentifier and noticed that they were called only after I selected the cell. If I cleaned my collection by displaying the selected cells before starting my application, then modelIdentifierForElementAtIndexPath will not be called, but once I set at least one cell. At least I can verify that you are not the only one who sees this behavior.

I think that due to the different nature of UICollectionView , it is probably not easy to create behavior that scrolls visible cells to the correct point, but this is not explicitly reflected in Apple's documentation. A good alternative would be to manually encode the identifier of the first visible cell for your layout. What I am doing is moving the collection scroll scroll offset to NSValue and restoring:

 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) } 
+5
source

Source: https://habr.com/ru/post/981945/


All Articles