【问题标题】:UICollectionView Items Data distorts after scrolling in Swift 4.2UICollectionView 项目数据在 Swift 4.2 中滚动后扭曲
【发布时间】:2018-11-14 07:34:30
【问题描述】:

我正在尝试使用 UICollectionView 实现聊天屏幕,并且数据按预期显示。但是,当我尝试滚动它几次时,我的数据会如屏幕截图中所解释的那样失真。谁能建议出了什么问题以及如何解决?谢谢!

首先显示:

滚动几次后显示:

我正在使用的与 UICollectionView 相关的所有方法的代码:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    let count = chatCategoriesArray.messages.count
    if count != 0 {
        return count
    }
    return 0
}

var allCellsHeight: CGFloat = 0.0
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ChatLogMessageCell
    cell.messageTextView.text = chatCategoriesArray.messages[indexPath.item]
    let size = CGSize(width: 250, height: 1000)
    let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
    let estimatedFrame = NSString(string: chatCategoriesArray.messages[indexPath.item]).boundingRect(with: size, options: options, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18)], context: nil)

    if chatCategoriesArray.senderIds[indexPath.item] == "s_\(self.studentInstance.tutorIdFound)"{
        cell.profileImageView.image = UIImage(named: "three.png")
        cell.profileImageView.isHidden = false
        cell.messageTextView.frame = CGRect(x: 48 + 8, y:0, width: estimatedFrame.width + 16, height: estimatedFrame.height + 20)
        cell.textBubbleView.frame = CGRect(x: 48, y: 0, width: estimatedFrame.width + 16 + 8, height: estimatedFrame.height + 20)
        self.currentCellWidth = Double(estimatedFrame.width + 16 + 8)
        cell.textBubbleView.backgroundColor = .white
        cell.addSubview(cell.profileImageView)
        cell.addConstraintsWithFormat(format: "H:|-8-[v0(30)]", views: cell.profileImageView)
        cell.addConstraintsWithFormat(format: "V:[v0(30)]|", views: cell.profileImageView)
    }
    else{
        cell.profileImageView.image = UIImage(named: "two.png")
        cell.textBubbleView.backgroundColor = UIColor(r: 28, g:168, b:261)
        cell.messageTextView.frame = CGRect(x: view.frame.width - estimatedFrame.width - 16 - 46, y:0, width: estimatedFrame.width + 16, height: estimatedFrame.height + 20)
        cell.messageTextView.textColor = .white
        cell.textBubbleView.frame = CGRect(x: view.frame.width - estimatedFrame.width - 16 - 8 - 46, y: 0, width: estimatedFrame.width + 16 + 8, height: estimatedFrame.height + 20)
        self.currentCellWidth = Double(estimatedFrame.width + 16 + 8)
        cell.addSubview(cell.profileImageView)
        cell.addConstraintsWithFormat(format: "H:[v0(30)]-8-|", views: cell.profileImageView)
        cell.addConstraintsWithFormat(format: "V:[v0(30)]|", views: cell.profileImageView)
    }
    allCellsHeight += cell.frame.height
    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    if allCellsHeight < (collectionView.frame.height){
        return UIEdgeInsets(top: view.frame.height - allCellsHeight, left: 0, bottom: 0, right: 0)
    }
    else {
        return UIEdgeInsets(top: 8, left: 0, bottom: 0, right: 0)
    }
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    let size = CGSize(width: 250, height: 1000)
    let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
    let estimatedFrame = NSString(string: chatCategoriesArray.messages[indexPath.item]).boundingRect(with: size, options: options, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18)], context: nil)
    return CGSize(width: view.frame.width, height: estimatedFrame.height + 20)
}

【问题讨论】:

  • 您不应该在cellForItemAt 中添加视图和约束,除非您首先删除之前添加的那些(单元格被重复使用!)。你的allCellsHeight 不会这样工作。 cellForItemAt 将为每个单元格调用多次,cell.frame.height 在此调用期间甚至都不正确。
  • 感谢@Sulthan,您的建议对我真的很有效,我怎样才能将您的建议标记为答案? ^_^
  • 我会把它转换成答案。

标签: swift scroll uicollectionview uicollectionviewcell


【解决方案1】:

收集单元被重复使用。这意味着当您向上/向下滚动时,不可见的单元格将从层次结构中删除并排队等待重用。然后集合视图再次调用cellForItem: 以获取可见的项目。 dequeueReusableCell 并不总是创建一个新实例。通常它只会返回一个已经变得不可见的单元格,以便您使用新数据重新设置它。

如果您在设置过程中添加视图/约束,则必须确保删除之前添加的视图/约束,否则单元格将具有重复的视图和冲突的约束。

还要注意allCellsHeight 不能这样工作。 cell.frame.height 在设置后(实际布局之前)不会立即正确,并且由于可以为同一项目多次调用该方法,因此您不能只添加到全局变量中。你应该改用collectionView.contentSize.height

【讨论】:

  • 谢谢!是的,在添加它们之前需要 .removeFromSuperview() 项目。
【解决方案2】:

这是典型的可重复使用的细胞问题。发生这种情况会导致集合视图重用您的接收方单元格设置来创建发送方消息框。

我建议您使用两个不同的单元格作为发送方和接收方。在首次加载时设置约束。这也会对性能产生积极影响。

查看下图以了解如何使用 2 单元格。

【讨论】:

  • 您能否详细解释一下我如何在一个 collectionView 中使用两个不同的单元格。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多