6

要素が移動する可能性のある 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 の使い方を誤解していませんか? バグはありますか?これを機能させるためのよりエレガントな、または正しい方法はありますか?

4

2 に答える 2

5

すでに指摘したUIDataSourceModelAssociationように、 a の可視オフセットの復元では機能しないようですがUICollectionView、選択したアイテムに対してのみ機能します。modelIdentifierForElementAtIndexPathと の両方にブレークポイントを設定しようとしindexPathForElementWithModelIdentifierましたが、セルを選択した後にのみ呼び出されることに気付きました。アプリをバックグラウンド化する前にコレクション ビューの選択したセルをクリアmodelIdentifierForElementAtIndexPathすると、呼び出されませんが、少なくとも 1 つのセルを選択済みとして設定すると呼び出されます。少なくとも、この動作を見ているのはあなただけではないことを確認できます.

さまざまな性質があるため、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)
}
于 2015-04-12T21:34:18.337 に答える