UITextView轮廓框创建后尺寸位置异常,文本截断问题求助
boundingRectWithSize计算文本高度时最后一行截断的问题 我之前也碰到过一模一样的问题!明明用了正确的NSStringDrawingOptions,结果最后一行文本还是被截断,折腾了好一会儿才找到几个关键原因,给你分析下:
1. 浮点高度被截断导致高度不足
boundingRect(with:options:attributes:context:)返回的height是精确的浮点值,但UICollectionView在布局cell时,会自动把这个高度取整(比如把25.3变成25),这就会导致实际高度不够容纳最后一行文本。
解决办法:对计算出的高度做向上取整处理,用ceil()函数确保高度足够:
return CGSize(width: view.frame.width, height: ceil(estimatedFrame.height))
2. 计算宽度与实际显示宽度不一致
你现在用view.frame.width作为计算的宽度,但如果你的cell里的文本label有左右内边距(比如cell的contentView有padding,或者label本身有layoutMargins),那实际文本可占用的宽度比view.frame.width要小。这时候用更大的宽度计算出来的高度会偏小,实际显示时文本行数变多,自然就截断了最后一行。
解决办法:用label实际可使用的宽度来计算,比如如果label左右各有16pt的padding,那计算的size应该是:
let availableWidth = view.frame.width - 16*2 let size = CGSize(width: availableWidth, height: 1000)
3. 字体设置不匹配
确保你计算时用的字体和cell中label实际显示的字体完全一致。比如你计算时用UIFont.systemFont(ofSize:18),但label里的字体是UIFont.systemFont(ofSize:18, weight: .medium),这种细微的差异也会导致高度计算不准。
修正后的完整代码示例
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { guard let messageText = messages?[indexPath.item].text else { return CGSize(width: view.frame.width, height: 100) } // 替换成你label实际可用的宽度 let availableWidth = view.frame.width - 32 // 假设左右各16pt padding let size = CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude) // 用最大高度代替固定1000,更稳妥 let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading] let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 18)] let estimatedFrame = NSString(string: messageText).boundingRect( with: size, options: options, attributes: attributes, context: nil ) // 向上取整,确保高度足够 return CGSize(width: view.frame.width, height: ceil(estimatedFrame.height)) }
另外,把高度参数换成CGFloat.greatestFiniteMagnitude比固定的1000更稳妥,能避免超长文本超出1000高度的情况。
内容的提问来源于stack exchange,提问作者Ninja

