使用MessageKit自定义消息时出现堆叠及滚动错位问题求助
MessageKit自定义消息堆叠&滚动位置错乱问题修复
问题现象
- 添加新自定义消息时,新消息与旧消息互相堆叠
- 滚动列表时,消息位置持续错乱,确认与单元格复用(dequeue reusable cell)机制相关
用户提供代码
1. CollectionView单元格配置代码
override open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let messagesDataSource = messagesCollectionView.messagesDataSource else { fatalError("nil data source for messages") } if isSectionReservedForTypingIndicator(indexPath.section) { return super.collectionView(collectionView, cellForItemAt: indexPath) } let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) if case .custom = message.kind { let cell = messagesCollectionView.dequeueReusableCell(withReuseIdentifier: "custom cell", for: indexPath) as! MyCustomCell cell.Chats = self cell.configure(with: message, at: indexPath, and: messagesCollectionView) return cell } return super.collectionView(collectionView, cellForItemAt: indexPath) } func numberOfItems(inSection section: Int, in messagesCollectionView: MessagesCollectionView) -> Int { return 1 }
2. 自定义尺寸计算器与布局代码
open class CustomMessageSizeCalculator: MessageSizeCalculator { public override init(layout: MessagesCollectionViewFlowLayout? = nil) { super.init() self.layout = layout } open override func messageContainerSize(for message: MessageType) -> CGSize { guard let layout = layout else { return .zero } let maxWidth = messageContainerMaxWidth(for: message) let contentInset = layout.collectionView?.contentInset ?? .zero let inset = layout.sectionInset.left + layout.sectionInset.right + contentInset.left + contentInset.right switch message.kind{ case .custom(let item): let constuctedUIV = UIView(CGRect(x:0,y:0, height:100, width:100)) return CGSize(width: maxWidth, height: constuctedUIV.frame.height + 30) break default: break; } return CGSize(width: ((maxWidth / 2) - inset), height: ((maxWidth / 4) - inset)) } } open class MyCustomMessagesFlowLayout: MessagesCollectionViewFlowLayout { lazy open var customMessageSizeCalculator = CustomMessageSizeCalculator(layout: self) open override func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator { let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) if case .custom = message.kind { return customMessageSizeCalculator } return super.cellSizeCalculatorForItem(at: indexPath) } open override func messageSizeCalculators() -> [MessageSizeCalculator] { var superCalculators = super.messageSizeCalculators() superCalculators.append(customMessageSizeCalculator) return superCalculators } }
修复方案
1. 解决单元格复用残留问题
自定义单元格复用时,旧内容未被清理会导致堆叠。在MyCustomCell的configure方法开头,先重置所有子视图:
func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { // 清除所有旧子视图,避免复用残留 contentView.subviews.forEach { $0.removeFromSuperview() } // 后续根据当前message配置新内容 // ... 你的自定义UI配置代码 }
2. 修正尺寸计算器逻辑
当前尺寸计算存在两处问题:创建的constuctedUIV未实际参与计算,默认返回的尺寸公式错误。修正后的方法:
open override func messageContainerSize(for message: MessageType) -> CGSize { guard let layout = layout else { return .zero } let maxWidth = messageContainerMaxWidth(for: message) let contentInset = layout.collectionView?.contentInset ?? .zero let totalHorizontalInset = layout.sectionInset.left + layout.sectionInset.right + contentInset.left + contentInset.right let availableWidth = maxWidth - totalHorizontalInset switch message.kind { case .custom(let item): // 替换为实际自定义内容的高度计算逻辑,示例用固定高度 let customContentHeight: CGFloat = 100 return CGSize(width: availableWidth, height: customContentHeight + 30) default: // 非自定义消息直接复用父类的计算逻辑 return super.messageContainerSize(for: message) } }
3. 确保单元格与布局正确注册
在视图控制器的viewDidLoad中,完成以下注册:
// 注册自定义单元格 messagesCollectionView.register(MyCustomCell.self, forCellWithReuseIdentifier: "custom cell") // 设置自定义布局 messagesCollectionView.collectionViewLayout = MyCustomMessagesFlowLayout()
4. 验证数据源逻辑
确保messagesDataSource的实现符合MessageKit规范,每个section对应一条消息,numberOfItems(inSection:)返回1是正确的。
内容的提问来源于stack exchange,提问作者Camille Basbous
相关产品推荐
相关产品推荐

