当我将新单元格添加到集合视图时,我不断收到布局错误

Posted

技术标签:

【中文标题】当我将新单元格添加到集合视图时,我不断收到布局错误【英文标题】:I keep on receiving a layout error when I add a new cell to a collection view 【发布时间】:2018-01-25 16:50:02 【问题描述】:

我正在尝试将数据从一个视图控制器添加到集合视图控制器,该控制器将元素添加到数据源数组,然后将单元格添加到集合视图。

prepareforsegue 之前的ViewController

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if segue.identifier == "unwindToCollectionView"
        let CVC = segue.destination as! CollectionViewController
        if let image = image
        CVC.images.insert(imagePost(image:image), at: 0)
            print("Image is not nil")
        
        let index = IndexPath(item: 0, section: 0)
        //CVC.collectionView?.reloadData()

        CVC.collectionView?.collectionViewLayout.invalidateLayout()
        CVC.collectionView?.layoutIfNeeded()
        CVC.collectionView?.insertItems(at: [index])
        //CVC.collectionView?.reloadItems(at: [index])
        print("In prepare for segue: \(CVC.images.count)")
    

collectionViewControllercellForItemAt

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
    // Configure the cell
    cell.cellImageView.image = images[indexPath.row].image

    cell.cellImageView.clipsToBounds = true
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
    layout.itemSize = CGSize(width: (UIScreen.main.bounds.width-1)/2, height: (UIScreen.main.bounds.width-1)/2)
    layout.minimumInteritemSpacing = 1
    layout.minimumLineSpacing = 1
    collectionView.collectionViewLayout = layout
    cell.cellImageView.layer.cornerRadius = CGFloat((cell.cellImageView.frame.width)/2)
    return cell

收到错误:

2018-01-25 11:43:16.228902-0500 CAR+CV(1.0)Server[4182:1181750] *** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无法设置布局 [] [;层 = ;内容偏移:0,-88;内容大小:375, 573; adjustedContentInset: 88, 0, 83, 0> 集合视图布局: ] 在更新期间。

【问题讨论】:

您为什么在prepareForSegue 中调用invalidateLayoutlayoutIfNeededinsertItems?另外我认为您不应该在cellForItemAtIndexPath 中设置UICollectionViewFlowLayout……为什么不使用UICollectionViewDelegateFlowLayout 协议中的方法? @shim 如果不在prepareForSegue 中,应该在哪里调用insertItems 当我尝试删除它并在collectionViewControllerviewDidLoad 内调用它时,我收到了有关索引的错误。 也许你误解了insertItems 的目的。您只需要设置cellForItemAtnumberOfItemsInSection 并且集合视图会自行处理插入项目。 insertItems 主要用于当您需要显示正在添加的新项目时 - 并且必须在集合视图的数据源中进行相应的更改。 @shim 我在 segue 之后传递了一个带有添加项的数组。当我不在prepareForSegue 中调用insertItems 时,collectionView 中不会生成新单元格 【参考方案1】:

这样做的方法非常错误......

首先,将您的collectionViewLayout 设置为viewDidLoad()

接下来,在prepareForSegue 中,您要修改集合视图的数据,而不是集合视图本身。

所以...

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if segue.identifier == "unwindToCollectionView"
        let CVC = segue.destination as! CollectionViewController
        if let image = image 
            // add the image to the CollectionViewController's data 
            CVC.images.insert(imagePost(image:image), at: 0)
            print("Image is not nil")
        
        print("In prepare for segue: \(CVC.images.count)")
    

那么,您的收藏视图的cellForItemAt 就是:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell

    // Configure the cell
    cell.cellImageView.image = images[indexPath.row].image

    // don't do this here...
    // cell.cellImageView.clipsToBounds = true
    // cell.cellImageView.layer.cornerRadius = CGFloat((cell.cellImageView.frame.width)/2)

    return cell


编辑: 作为旁注,设置.cornerRadius 也不应该在cellForItemAt 中完成,因为单元格还不会被布局。更好地继承 UIImageView 并在 layoutSubviews() 中设置 .cornerRadius


编辑 2:

class RoundImageView: UIImageView 

    override func layoutSubviews() 
        super.layoutSubviews()

        self.clipsToBounds = true
        self.layer.cornerRadius = self.frame.width / 2.0

    


只需将您当前的 UIImageView 的 Class 设置为 RoundImageView

“我在哪里调用 insertItems(at:[index])”

您不需要这样做。当您的 segue 移动到视图控制器时,您的集合视图将重新加载,并且您刚刚插入 images 数组的图像将成为第一个单元格。我注意到您的 segue 标识符是 "unwindToCollectionView" - 因此,如果您的集合视图自动重新加载,请将其添加到持有集合视图的 VC:

override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)
    collectionView.reloadData()

【讨论】:

感谢您的回复,非常有帮助。除了更新 collectionViewController 中的数组外,我已将布局移至 viewDidLoad 并从 prepareForSegue 中删除了所有内容。但是我在哪里调用insertItems(at:[index]) 以便collectionView 为数组中的新元素添加一个新单元格。什么不会在cellForItemAt 中设置cornerRadius 看起来我必须覆盖layoutSubviews @user372382 - 请参阅我的回答中的 Edit 2 感谢您的编辑,现在代码可以正常工作,这对您很有帮助。是否可以使用collectionView.reloadItems(at: [IndexPath]) 而不是collectionView.reloadData() 从逻辑上考虑...假设您的集合视图如下所示:A | B | C | D(您的 images 数组)...您正在将 Z 插入数组中的位置 0 .如果您只使用.reloadItems(at: [IndexPath]),您的收藏视图将如下所示:Z | B | C | D。那是你想要的目标吗?还是您希望结果为Z | A | B | C | D?我怀疑是后者,在这种情况下你想要.reloadData()

以上是关于当我将新单元格添加到集合视图时,我不断收到布局错误的主要内容,如果未能解决你的问题,请参考以下文章

当我在收藏视图中滚动时,我的自定义单元格中的 UIView 锚点不断变化

集合视图单元格的自动布局行为怪异

将数据从集合视图单元格移动到新的集合视图单元格

集合视图,具有自定义布局,单元格在滚动时行为不端

iOS6 自动布局异常

在另一个集合视图的单元格内插入集合视图