我有一个导航控制器,在viewDidAppear上它会推送一个名为SingleBlueSquareCollectionViewController的UICollectionViewController。有一个蓝色正方形UICollectionViewCell定位中心,位于collectionView的底部。当你点击蓝色单元格时,我推送另一个CollectionViewController,TriangleCollectionViewController,它将蓝色方块放在顶部和中心,并在viewController的任一角添加两个红色单元格。这是我期望发生的,但我得到了一个NSInconsistencyError: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)
}
}