如何消除多行富文本Label中的空白区域?
我刚复现了你的问题,确实挺闹心的——当多行富文本Label设为居中对齐时,背景色会铺满每行的整个可用宽度,看起来就像空白区域也被涂黑了。这其实是因为UIKit绘制富文本背景色时,是按每行的排版边界来填充的,而不是只包围文字本身。
下面给你两种实用的解决方案,按需选择:
方案1:让Label宽度适配文字实际宽度,Label整体居中
这是最简单的解决思路:不让文字在Label内部居中,而是让Label本身在父视图里居中,同时Label的宽度刚好匹配文字实际占据的宽度,这样背景色就只会覆盖文字部分。
修改你的lbl()方法即可:
func lbl() { let text = "the fox is foxy and likes to run fast through the forest" let attributes: [NSAttributedString.Key: Any] = [ .foregroundColor: UIColor.yellow, .backgroundColor: UIColor.black, .font: UIFont.boldSystemFont(ofSize: 20.0) ] let attributedText = NSMutableAttributedString(string: text, attributes: attributes) // 计算富文本在最大宽度限制下的实际尺寸 let maxWidth = view.bounds.width - 32 // 对应你原来的左右间距 let textSize = attributedText.boundingRect( with: CGSize(width: maxWidth, height: .greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil ).size itemLabel.attributedText = attributedText itemLabel.font = UIFont.boldSystemFont(ofSize: 20.0) itemLabel.textAlignment = .left // 改成左对齐,Label本身会居中 itemLabel.numberOfLines = 2 itemLabel.lineBreakMode = .byTruncatingTail itemLabel.isUserInteractionEnabled = false itemLabel.translatesAutoresizingMaskIntoConstraints = false view.addSubview(itemLabel) // 设置约束:Label居中,尺寸匹配文字实际大小 NSLayoutConstraint.activate([ itemLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), itemLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), itemLabel.widthAnchor.constraint(equalToConstant: ceil(textSize.width)), itemLabel.heightAnchor.constraint(equalToConstant: ceil(textSize.height)) ]) }
方案2:自定义富文本背景绘制(更灵活)
如果需要保留Label的宽范围限制(比如允许Label宽度大于文字宽度,但背景色只包裹文字),可以用Core Text手动绘制富文本,精确控制背景色的范围。
先创建一个自定义View:
class CustomTextLabel: UIView { var attributedText: NSAttributedString? { didSet { setNeedsDisplay() } } var numberOfLines = 2 override func draw(_ rect: CGRect) { super.draw(rect) guard let attributedText = attributedText else { return } let frameSetter = CTFramesetterCreateWithAttributedString(attributedText as CFAttributedString) let path = CGMutablePath() path.addRect(bounds) let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, attributedText.length), path, nil) let lines = CTFrameGetLines(frame) as [AnyObject] var lineOrigins = [CGPoint](repeating: .zero, count: lines.count) CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), &lineOrigins) // 遍历每行,先画背景色再画文字 for (index, line) in lines.enumerated() { if index >= numberOfLines { break } let line = line as! CTLine let lineRect = CTLineGetImageBounds(line, UIGraphicsGetCurrentContext()) let origin = lineOrigins[index] // 绘制背景色:只覆盖文字实际宽度 let bgRect = CGRect( x: origin.x + lineRect.origin.x, y: origin.y + lineRect.origin.y, width: lineRect.width, height: lineRect.height ) UIColor.black.setFill() bgRect.fill() // 绘制文字 UIGraphicsGetCurrentContext()?.saveGState() UIGraphicsGetCurrentContext()?.textMatrix = .identity UIGraphicsGetCurrentContext()?.translateBy(x: origin.x, y: origin.y + bounds.height - lineRect.origin.y - lineRect.height) UIGraphicsGetCurrentContext()?.scaleBy(x: 1, y: -1) CTLineDraw(line, UIGraphicsGetCurrentContext()!) UIGraphicsGetCurrentContext()?.restoreGState() } } }
然后在ViewController里替换原来的UILabel:
class ViewController: UIViewController { let itemLabel = CustomTextLabel() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.white lbl() } func lbl() { let text = "the fox is foxy and likes to run fast through the forest" let attributes: [NSAttributedString.Key: Any] = [ .foregroundColor: UIColor.yellow, .font: UIFont.boldSystemFont(ofSize: 20.0) ] itemLabel.attributedText = NSMutableAttributedString(string: text, attributes: attributes) itemLabel.numberOfLines = 2 itemLabel.translatesAutoresizingMaskIntoConstraints = false view.addSubview(itemLabel) NSLayoutConstraint.activate([ itemLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), itemLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), itemLabel.widthAnchor.constraint(lessThanOrEqualTo: view.widthAnchor, constant: -32) ]) } }
简单总结:如果只是解决当前的空白问题,方案1足够高效;如果需要更灵活的排版控制(比如复杂的文字高亮、自定义行间距),方案2更合适。
内容的提问来源于stack exchange,提问作者ctrl freak
相关产品推荐
相关产品推荐

