Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/117.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UICollectionView状态恢复:自定义滚动位置_Ios_Swift_Uicollectionview_State Restoration_Uikit State Preservation - Fatal编程技术网

Ios UICollectionView状态恢复:自定义滚动位置

Ios UICollectionView状态恢复:自定义滚动位置,ios,swift,uicollectionview,state-restoration,uikit-state-preservation,Ios,Swift,Uicollectionview,State Restoration,Uikit State Preservation,我试图找到处理UICollectionView状态恢复的最佳方法,因为UICollectionView的元素可能会四处移动我的目标是确保在重新启动应用程序时,集合视图中最后一次查看的项目仍然可见,即使项目已移动。例如,当应用程序被终止时,项目A位于索引3的单元格中,如果模型说项目A应显示在索引4,则当应用程序重新启动时,我希望集合视图初始化索引4处单元格的偏移量 我认为在我的UICollectionViewDataSource类中实现UIDataSourceModelAssociation协议将

我试图找到处理UICollectionView状态恢复的最佳方法,因为UICollectionView的元素可能会四处移动我的目标是确保在重新启动应用程序时,集合视图中最后一次查看的项目仍然可见,即使项目已移动。例如,当应用程序被终止时,项目A位于索引3的单元格中,如果模型说项目A应显示在索引4,则当应用程序重新启动时,我希望集合视图初始化索引4处单元格的偏移量

我认为在我的
UICollectionViewDataSource
类中实现
UIDataSourceModelAssociation
协议将为我解决这个问题,如下所述:

[UITableView和UICollectionView]类使用此协议的方法来确保将相同的数据对象(而不仅仅是相同的行索引)滚动到视图中并选中

然而,我所观察到的是,在恢复过程中,实现此协议确实会正确地影响选定单元格的Indexath(这对我的应用程序并不重要),但不会影响滚动位置。滚动位置(集合视图的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的用法?有虫子吗?有没有更优雅或正确的方法来实现这一点?

正如您已经指出的,
UIDataSourceModelAssociation
似乎无法恢复
UICollectionView
的可见偏移量,但只能恢复选定的项。我尝试在
modelnidentifierforelementatindexpath
indexpathForelementwithmodelnidentifier
上设置断点,并注意到只有在选择单元格后才会调用断点。如果我在将我的应用程序回退之前清除了集合视图的选定单元格,则不会调用
modelnidentifierforelementatindexpath
,但一旦我将至少一个单元格设置为选定单元格,就会调用它。至少我可以证实你不是唯一一个看到这种行为的人

我认为,由于
UICollectionView
的不同性质,创建将可见单元格滚动到正确点的行为可能并不简单,但这显然没有反映在苹果的文档中。手动将标识符编码到布局的第一个可见单元格应该是一个不错的选择。我所做的是将集合视图的滚动偏移量包装在一个
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)
    }

正如我在ExpathForElementWithModelIdentifier:inView中看到的那样:设计用于做同样的事情。它有效吗?@orkenstein我试过用它,但没用。请参阅我的OP:“在恢复过程中,实现此协议确实会正确地影响选定单元格的indexPath(这对我的应用程序并不重要),但不会影响滚动位置。”良好的分析。这对我来说是有意义的。这是可行的,但在错误的位置恢复了偏移量--这可能是导航栏计算出了问题。您可以使用encodeCGPoint(),无需使用NSValue@stephanek. 我将代码改写如下:但它似乎根本不起作用。请问我是否遗漏了什么?谢谢我在下面的答案中发布了格式化代码。@stephanek。重写func encodeRestorableState(带编码器:NSCoder){super.encodeRestorableState(带编码器:coder)coder.encode(collectionView.contentOffset,forKey:“CollectionViewContentOffset”)}重写func decodeRestorableState(带编码器:NSCoder){super.decodeRestorableState(带编码器)让offsetValue=coder.decodeObject(forKey:“CollectionViewOffset”)为!CGPoint collectionView?.setContentOffset(offsetValue,动画:false)}您应该使用decodePoint,它是一个CGPoint,不是一个对象:-)OMG,我测试了decodeCGPoint,它就像一个符咒。谢谢