两个UICollectionView布局之间的转换会导致不一致错误

时间:2017-07-14 11:52:03

标签: swift uicollectionview uikit uicollectionviewlayout

我有一个导航控制器,在viewDidAppear上它会推送一个名为SingleBlueSquareCollectionViewController的UICollectionViewController。有一个蓝色正方形UICollectionViewCell定位中心,位于collectionView的底部。当你点击蓝色单元格时,我推送另一个CollectionViewController,TriangleCollectionViewController,它将蓝色方块放在顶部和中心,并在viewController的任一角添加两个红色单元格。这是我期望发生的,但我得到了一个N​​SInconsistencyError:UICollectionView接收了一个索引路径不存在的单元格的布局属性。

错误是有道理的。一个视图控制器有一个元素,但另一个视图控制器有3.但我不希望triangleViewController从SingleBlue获取信息。有没有解决的办法?而且更大的问题是你能在具有不同数量元素的两个布局之间转换吗?

如果是这样,我做错了什么?我该怎么办呢?是否有动画对象来提供我的collectionViews?这个用例是我想要在另一个应用程序中尝试的东西的测试,该应用程序具有一些具有一些复杂布局的视图控制器(所以我完全理解这个用例可以用一些UIViews完成,并且可以轻松地围绕蓝色方块等动画)

这里有一些源代码:

class SingleBlueSquare: UICollectionViewLayout {

var cache : [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]()

override func prepare() {
    configureCache()
}

override var collectionViewContentSize: CGSize { return CGSize(width: collectionView!.frame.width,
                                                      height: collectionView!.frame.height)   }

override func prepareForTransition(from oldLayout: UICollectionViewLayout) {
    configureCache()
}


func configureCache() {
    guard let collection = collectionView else {return}
    let first = IndexPath(item: 0, section: 0)

    let blue = UICollectionViewLayoutAttributes(forCellWith: first)

    let size : CGSize = .init(width: 50, height: 50)

    blue.frame = CGRect(origin: .init(x: collection.frame.width/2,
                                      y: collection.frame.height - size.height),
                        size: size)

    cache = [blue]
}

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return cache[indexPath.item]
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return cache
}

TriangleLayout

class TriangleLayout: UICollectionViewLayout {

var cache : [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]()

override func prepare() {
    configureCache()
}

override func prepareForTransition(to newLayout: UICollectionViewLayout) {
    cache.removeAll()
}

override var collectionViewContentSize: CGSize { return CGSize(width: collectionView!.frame.width,
                                                               height: collectionView!.frame.height)   }

override func prepareForTransition(from oldLayout: UICollectionViewLayout) {
    configureCache()
}

func configureCache() {
    guard let collection = collectionView else {return}
    cache.removeAll()
    let first = IndexPath(item: 0, section: 0)
    let second = IndexPath(item: 1, section: 0)
    let third = IndexPath(item: 2, section: 0)
    let blue = UICollectionViewLayoutAttributes(forCellWith: first)
    let red = UICollectionViewLayoutAttributes(forCellWith: second)
    let red2 = UICollectionViewLayoutAttributes(forCellWith: third)

    let size : CGSize = .init(width: 50, height: 50)

    blue.frame = CGRect(origin: .init(x: collection.frame.width/2,
                                      y: 0),
                        size: size)
    red.frame = CGRect(origin: .init(x: 0,
                                     y: collection.frame.height - 50),
                       size: size)

    red2.frame = CGRect(origin: .init(x: collection.frame.width - 50,
                                      y: collection.frame.height - 50),
                        size: size)



    cache = [blue, red, red2]

}

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return cache[indexPath.item]
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return cache
}



}

SingleCollectionViewController

private let reuseIdentifier = "blue"

class SingleBlueCollectionViewController: UICollectionViewController {

init() {
    super.init(collectionViewLayout: SingleBlueSquare())

    useLayoutToLayoutNavigationTransitions = false
}

override init(collectionViewLayout layout: UICollectionViewLayout) {
    super.init(collectionViewLayout: layout)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

override func viewDidLoad() {
    super.viewDidLoad()

    self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)


    self.collectionView?.reloadData()
    self.collectionView?.layoutIfNeeded()

}

// MARK: UICollectionViewDataSource


override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 1
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)

    cell.backgroundColor = indexPath.item == 0 ? UIColor.blue : UIColor.red
    return cell
}

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let cell = collectionView.cellForItem(at: indexPath), cell.backgroundColor == UIColor.blue else {return}
    collectionView.collectionViewLayout.invalidateLayout()
    navigationController?.pushViewController(TriangleCollectionViewController(), animated: true)
}

}

这是三角视图控制器

private let reuseIdentifier = "triangle"
class TriangleCollectionViewController : SingleBlueCollectionViewController {


override init() {
    super.init(collectionViewLayout: TriangleLayout())
    useLayoutToLayoutNavigationTransitions = true
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

override func viewDidLoad() {
    super.viewDidLoad()


    // Register cell classes
    self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)

    self.collectionView?.reloadData()
    self.collectionView?.collectionViewLayout.invalidateLayout()

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

// MARK: UICollectionViewDataSource

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 3
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)

    cell.backgroundColor = indexPath.item == 0 ? UIColor.blue : UIColor.red
    return cell
}


override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let cell = collectionView.cellForItem(at: indexPath), cell.backgroundColor == UIColor.blue else {return}
    navigationController?.popViewController(animated: true)
}
}

0 个答案:

没有答案