如何保持 CollectionView 单元格返回查看

Posted

技术标签:

【中文标题】如何保持 CollectionView 单元格返回查看【英文标题】:How to keep CollectionView cells on return to view 【发布时间】:2017-07-10 04:00:51 【问题描述】:

我有一个 CollectionView,它的单元格对应于 Firebase 数据库中的子项。我的问题是,当我转入另一个视图,然后转回时,CollectionView 单元格消失了。

我有一个 cellForItemAt 函数:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "playerItem", for: indexPath) as! PlayerCollectionViewCell
    cell.setupViews(parentSize: Int(self.playerCollectionView.frame.width), hostUID: self.currentUID, tempUserName: playerArrayList[indexPath.item])
    cell.layer.cornerRadius = 6
    cell.layer.borderWidth = 2
    return cell

我还有另一个代码片段:

for i in 0..<playerArrayList.count
    print(playerCollectionView.numberOfItems(inSection: 0))
    //playerCollectionView.insertItems(at: [IndexPath(item: i, section: 0)])
    let cell = playerCollectionView.cellForItem(at: IndexPath(item: i, section: 0)) as! PlayerCollectionViewCell
    cell.tempUserName = playerArrayList[i]
    cell.setupViews(parentSize: Int(self.playerCollectionView.frame.width), hostUID: self.currentUID, tempUserName: playerArrayList[i])

我仍在学习 CollectionView 如何创建单元格,以及当 View 处于休眠状态时程序会做什么,但我相信我的问题是 cellForItemAt 函数在第一次创建视图时创建了所有单元格并且不会发生之后再次。 我确信这一点,因为当第一次创建视图时,有三个单元格(这正是数据库中有多少孩子)但是当回到同一个视图时,没有单元格。 我试图通过删除所有单元格然后重新制作它们来解决这个问题。 在代码sn-p中,可以看到注释行:

playerCollectionView.insertItems(at: [IndexPath(item: i, section: 0)])

但是这给了我错误:

由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:第0节中的项目数无效。更新后现有节中包含的项目数(3)必须等于项目数更新前包含在该部分中 (3),加上或减去从该部分插入或删除的项目数(0 插入,1 个删除),加上或减去移入或移出该部分的项目数(0 移入, 0 移出)。'

我也试过用它来创建单元格:

let cell = playerCollectionView.dequeueReusableCell(withReuseIdentifier: "playerItem", for: IndexPath(item: i, section: 0)) as! PlayerCollectionViewCell

但我得到了同样的错误。如何在返回视图时重新创建单元格?

【问题讨论】:

你是怎么回去的?您确定您不会继续使用原始视图控制器的新实例吗? @Paulw11 我正在切换的两个视图在同一个堆栈中,所以我很确定它不是一个新实例。 drive.google.com/file/d/0B5SQeKTVAsVbSEFweEw0dURVejQ/… segues 本身是从视图控制器到视图控制器而不是按钮到视图控制器,因为我需要在 segue 之前执行操作。 如果您没有在导航控制器中使用“后退”按钮,那么您必须确保使用展开转场,否则您会不断推送视图控制器的新实例。在viewDidLoad 中放置一个日志语句或断点,如果它被多次调用,那么您正在创建一个新实例。 @Paulw11 我正在使用后退按钮,并且我使用 print 语句来确定 viewDidLoad 被多次调用。如何恢复第一个实例或终止后退按钮上的当前实例?我正在使用从主菜单视图到当前视图的显示转场,而不是按钮转场。我需要改变segue的类型吗?如果有的话是什么类型的? 【参考方案1】:

检查您是否在 UICollectionViewDataSource 对象中实现方法 collectionView(_:numberOfItemsInSection:)collectionView(_:cellForItemAt:)

当使用cellForItem 访问单元格时,您应该检查您是否真的得到了一个单元格。该方法只返回可见单元格。

if let cell = self.playerCollectionView.cellForItem(at: indexPath) as? PlayerCollectionViewCell 
    cell.tempUserName = playerArrayList[i]
    cell.setupViews(parentSize: Int(self.playerCollectionView.frame.width), hostUID: self.currentUID, tempUserName: playerArrayList[i])

你应该有一个集合视图的委托,而不是再次插入单元格,它告诉有多少项目要显示

override function viewDidLoad() 
    super.viewDidLoad()
    playerCollectionView.dataSource = self


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    return playerArrayList.count

insertItemsAt 方法要求您更新来自 numberOfItemsInSection 的返回值以匹配新的项目数。

如果playerArrayList 对象需要重新加载,您可以执行该生命周期方法

override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)
    // reload

【讨论】:

我已经添加了 if 语句来检查我是否收到了一个单元格,并且我已经添加了一个重新加载到 viewWillAppear。我已经有了 numberOfItemsInSection 函数,但我没有提到它,因为我不相信这是问题所在。好消息是我没有收到任何错误,但是现在有两倍的单元格。数组 playerArrayList 只有 3 个项目,但 Collection View 中有 6 个单元格。可能是什么问题呢? @米卡 好的,我们已经完成了一半 :) 我无法从此处提供的代码中判断可能是什么问题。也许查看 cell.setupViews 方法中的代码并检查它是否清除了任何视图,或者之前对该方法的调用可能已添加。此外,搜索重复集合视图单元格的答案可能会提供单元格重复的典型情况。【参考方案2】:

你想在 viewWillAppear 方法中重新加载集合视图

【讨论】:

以上是关于如何保持 CollectionView 单元格返回查看的主要内容,如果未能解决你的问题,请参考以下文章

从popover返回后如何在collectionview单元格中填充文本字段

关闭视图后如何保持集合视图单元格的状态?

一个collectionview单元格中有两个UIImage?

Swift 3 - CollectionView 数据源未返回有效单元格

表格单元格中的集合视图。这是重用的错误

如何滚动到第一个单元格,同时在 CollectionView 上滑动最后一个单元格?