UICollectionView项目数据在Swift 4.2中滚动后失真

UICollectionView项目数据在Swift 4.2中滚动后失真,swift,scroll,uicollectionview,uicollectionviewcell,Swift,Scroll,Uicollectionview,Uicollectionviewcell,我正在尝试使用UICollectionView实现聊天屏幕,数据按预期显示。然而,当我尝试滚动几次时,我的数据就会像截图中解释的那样失真。有人能建议出了什么问题以及如何解决吗?谢谢 首先,它表明: 滚动几次后显示: 我正在使用的与UICollectionView相关的所有方法的代码: func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

我正在尝试使用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)
}
func collectionView(collectionView:UICollectionView,numberofitemsinssection:Int)->Int{
let count=chatCategoriesArray.messages.count
如果计数!=0{
返回计数
}
返回0
}
var allCellsHeight:CGFloat=0.0
func collectionView(collectionView:UICollectionView,cellForItemAt indexPath:indexPath)->UICollectionViewCell{
让cell=collectionView.dequeueReusableCell(withReuseIdentifier:cellId,for:indexPath)作为!ChatLogMessageCell
cell.messageTextView.text=chatCategoriesArray.messages[indexPath.item]
let size=CGSize(宽:250,高:1000)
let options=NSStringDrawingOptions.UseSFuntleding.union(.usesLineFragmentOrigin)
让estimatedFrame=NSString(字符串:chatCategoriesArray.messages[indexPath.item]).boundingRect(带:大小、选项:选项、属性:[NSAttributeString.Key.font:UIFont.systemFont(of size:18)],上下文:nil)
if chatCategoriesArray.senderIds[indexPath.item]=“s_ \(self.studentInstance.tutorialdfound)”{
cell.profileImageView.image=UIImage(名为:“three.png”)
cell.profileImageView.ishiden=false
cell.messageTextView.frame=CGRect(x:48+8,y:0,宽度:estimatedFrame.width+16,高度:estimatedFrame.height+20)
cell.textbubleview.frame=CGRect(x:48,y:0,宽度:estimatedFrame.width+16+8,高度:estimatedFrame.height+20)
self.currentCellWidth=Double(估计帧宽度+16+8)
cell.textBubbleView.backgroundColor=.white
cell.addSubview(cell.profileImageView)
cell.addConstraintsWithFormat(格式:“H:|-8-[v0(30)]”,视图:cell.profileImageView)
cell.addConstraintsWithFormat(格式:“V:[v0(30)]|”,视图:cell.profileImageView)
}
否则{
cell.profileImageView.image=UIImage(名为:“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.textbubleview.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(估计帧宽度+16+8)
cell.addSubview(cell.profileImageView)
cell.addConstraintsWithFormat(格式:“H:[v0(30)]-8-|”,视图:cell.profileImageView)
cell.addConstraintsWithFormat(格式:“V:[v0(30)]|”,视图:cell.profileImageView)
}
AllCellsHigh+=cell.frame.height
返回单元
}
func collectionView(uCollectionView:UICollectionView,布局collectionViewLayout:UICollectionViewLayout,InsertForSectionat section:Int)->UIEdgeInsets{
如果所有单元高度<(集合视图.框架.高度){
返回UIEdgeInsets(顶部:view.frame.height-allCellsHeight,左侧:0,底部:0,右侧:0)
}
否则{
返回UIEDGEINSET(顶部:8,左侧:0,底部:0,右侧:0)
}
}
func collectionView(collectionView:UICollectionView,布局collectionViewLayout:UICollectionViewLayout,sizeForItemAt indexPath:indexPath)->CGSize{
let size=CGSize(宽:250,高:1000)
let options=NSStringDrawingOptions.UseSFuntleding.union(.usesLineFragmentOrigin)
让estimatedFrame=NSString(字符串:chatCategoriesArray.messages[indexPath.item]).boundingRect(带:大小、选项:选项、属性:[NSAttributeString.Key.font:UIFont.systemFont(of size:18)],上下文:nil)
返回CGSize(宽度:view.frame.width,高度:estimatedFrame.height+20)
}

这是典型的可重复使用单元故障。发生这种情况的原因是集合视图重用接收方单元格设置以创建发送方消息框

我建议您使用两个不同的手机作为发送方和接收方。在第一次加载时设置约束。这也将对绩效产生积极影响

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


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

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


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

请您详细解释一下如何在一个collectionView中使用两个不同的单元格。您不应该在
cellForItemAt
中添加视图和约束,除非您先删除之前添加的视图和约束(单元格被重用!)。您的
allCellsHeight
无法以这种方式工作
cellForItemAt
将为每个单元格调用多次,并且在此调用期间,
cell.frame.height
甚至不正确。谢谢@Sulthan您的建议