前言
针对超过指定行数显示展开,点击后显示全文,简单封装了一个控件,在此抛砖引玉供大家参考。
特性
- 支持富文本
- 支持内边距
- 支持
AutoLayout
原理
使用CoreText
切割字符串后,计算截断符的宽度,按照宽度重新生成新的字符串。这里核心在于如何保障新的字符串不会超出设置的行数。核心代码参考如下:
func reload() {
guard let attributedText = attributedText?.addAttributes({ $0.font(textLabel.font) }) else { return }
guard Thread.isMainThread else { return DispatchQueue.main.async { self.reload() } }
setNeedsLayout()
layoutIfNeeded()
let width = textLabel.bounds.width
let lines = attributedText.lines(width)
if numberOfLines > 0,
lines.count >= numberOfLines {
let additionalAttributedText = isOpen ? truncationToken.close : truncationToken.open
let length = lines.prefix(numberOfLines).reduce(0, { $0 + CTLineGetStringRange($1).length })
textLabel.attributedText = additionalAttributedText
let truncationTokenWidth = textLabel.sizeThatFits(.zero).width
let maxLength = isOpen ? attributedText.length : min(CTLineGetStringIndexForPosition(lines[numberOfLines - 1], CGPoint(x: width - truncationTokenWidth, y: 0)), length) - 1
displayAttributedText = {
let attributedText = NSMutableAttributedString(attributedString: attributedText.attributedSubstring(from: NSRange(location: 0, length: maxLength)))
attributedText.append(additionalAttributedText)
return attributedText
}()
}
textLabel.attributedText = displayAttributedText
}
效果图
Demo
核心代码已经贴出,完整代码请查看----->>>GitHub,如果对你有所帮助,欢迎Star。