运行时根据输入文本计算自定义CollectionView Cell的尺寸
针对MessageKit自定义输入状态Cell的高度适配方案
核心思路
自定义输入状态Cell的高度需根据文本内容动态计算,关键是重写MessageKit的尺寸计算方法,结合文本宽高计算逻辑实现适配。
具体实现步骤
1. 自定义Cell的布局配置
先在自定义输入状态Cell中配置好文本控件的约束与属性,确保文本能自动换行:
class CustomTypingCell: TypingIndicatorCell { let messageLabel = UILabel() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupLabelConstraints() } private func setupLabelConstraints() { messageLabel.numberOfLines = 0 messageLabel.lineBreakMode = .byWordWrapping messageLabel.font = UIFont.systemFont(ofSize: 16) contentView.addSubview(messageLabel) messageLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ messageLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), messageLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), messageLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), messageLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8) ]) } func updateText(_ text: String) { messageLabel.text = text } }
2. 重写尺寸计算方法
在MessagesViewController中,重写Cell尺寸计算方法,结合文本内容算出动态高度:
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { guard let item = messagesCollectionView.messagesDataSource?.messageItem(at: indexPath, in: messagesCollectionView) else { return super.collectionView(collectionView, layout: collectionViewLayout, sizeForItemAt: indexPath) } // 判断是否为输入状态Cell if item is TypingIndicatorItem { let displayText = yourTypingTextSource // 替换为你的输入文本数据源 let maxTextWidth = view.bounds.width - 32 // 对应Cell内label的左右16pt间距 // 计算文本高度 let textHeight = displayText.calculateHeight(with: maxTextWidth, font: UIFont.systemFont(ofSize: 16)) // 返回Cell总高度:文本高度+上下内边距 return CGSize(width: view.bounds.width, height: textHeight + 16) } return super.collectionView(collectionView, layout: collectionViewLayout, sizeForItemAt: indexPath) } // 给String扩展文本高度计算方法 extension String { func calculateHeight(with constrainedWidth: CGFloat, font: UIFont) -> CGFloat { let rect = CGSize(width: constrainedWidth, height: .greatestFiniteMagnitude) let boundingBox = self.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil) return ceil(boundingBox.height) } }
3. 文本更新时刷新布局
当其他用户输入文本变化时,更新数据源并刷新Cell:
func refreshTypingCell(with newText: String) { yourTypingTextSource = newText // 定位输入状态Cell的位置(通常在最后一个section的第一个item) let indexPath = IndexPath(item: 0, section: messagesCollectionView.numberOfSections - 1) messagesCollectionView.reloadItems(at: [indexPath]) messagesCollectionView.layoutIfNeeded() }
4. 数据源传递文本
在MessagesDataSource的实现中,给自定义Cell传入文本:
func typingIndicatorView(for messagesCollectionView: MessagesCollectionView) -> TypingIndicatorView { let cell = messagesCollectionView.dequeueReusableCell(CustomTypingCell.self, for: IndexPath(item: 0, section: messagesCollectionView.numberOfSections - 1)) cell.updateText(yourTypingTextSource) return cell }
注意事项
- 计算文本高度时,要保证使用的字体与Cell内Label的字体完全一致,避免高度偏差
- 如果Cell内还有加载动画等其他元素,计算总高度时要加上这些元素的高度和间距
- 文本频繁变化时可添加防抖处理(比如延迟0.2秒再刷新),避免布局抖动

内容的提问来源于stack exchange,提问作者Vishal
相关产品推荐
相关产品推荐

