Восстановление состояния UICollectionView: настройка положения прокрутки
Я пытаюсь найти лучший способ обработки восстановления состояния для UICollectionView, элементы которого могут перемещаться. Моя цель - убедиться, что последний просмотренный элемент в представлении коллекции все еще виден при перезапуске приложения, даже если элементы перемещались. Например, элемент A находится в ячейке с индексом 3, когда приложение было убито, и когда приложение перезапускается, если модель говорит, что элемент A должен отображаться с индексом 4, я хочу, чтобы представление коллекции инициализировало смещение для ячейки с индексом 4.,
Я думал, что реализация UIDataSourceModelAssociation
протокол в моем UICollectionViewDataSource
класс позаботится об этом для меня, как говорится в документации:
Классы [UITableView и UICollectionView] используют методы этого протокола, чтобы гарантировать, что одни и те же объекты данных (а не только одинаковые индексы строк) прокручиваются в представление и выбираются.
Однако я заметил, что реализация этого протокола правильно влияет на indexPath выбранных ячеек во время восстановления (что не важно для моего приложения), но не влияет на позицию прокрутки. Позиция прокрутки (contentOffset представления коллекции) всегда восстанавливается точно в том месте, где она была, когда приложение было убито, и не зависит от UICollectionViewDataSource.
У меня есть обходной путь, который выглядит следующим образом. Это в основном тот же шаблон, что и для протокола связывания моделей, но я должен сделать это вручную:
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)
}
}
}
Я неправильно понял использование UIDataSourceModelAssociation? Есть ли ошибка? Есть ли более элегантный или правильный способ заставить это работать?
1 ответ
Как вы уже отметили, UIDataSourceModelAssociation
похоже не работает с восстановлением UICollectionView
видимое смещение, но только для выбранных элементов. Я пытался установить точки останова на обоих modelIdentifierForElementAtIndexPath
а также indexPathForElementWithModelIdentifier
и заметил, что они были вызваны только после того, как я выбрал камеру. Если я очистил выбранные ячейки представления моей коллекции перед созданием фона моего приложения, то modelIdentifierForElementAtIndexPath
не будет вызван, но я бы однажды установил хотя бы одну ячейку в качестве выбранной. По крайней мере, я могу убедиться, что вы не единственный, кто видит такое поведение.
Я думаю из-за меняющейся природы UICollectionView
вероятно, не так просто создать поведение, которое прокручивает видимые ячейки до нужной точки, но это явно не отражено в документации Apple. Кодирование идентификатора в первую видимую ячейку для вашего макета вручную должно быть хорошей альтернативой. То, что я делаю, это оборачиваем смещение прокрутки представления коллекции в NSValue
и восстановить это:
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)
}
Обновление на основе предложения @stepane с помощью CGPoint.
override func encodeRestorableState(with coder: NSCoder) {
super.encodeRestorableState(with: coder)
coder.encode(collectionView.contentOffset, forKey: "CollectionViewContentOffset")
}
override func decodeRestorableState(with coder: NSCoder) {
super.decodeRestorableState(with: coder)
let offsetValue = coder.decodeObject(forKey: "CollectionViewOffset") as! CGPoint
collectionView?.setContentOffset(offsetValue, animated: false)
}