能否用AttributedString实现延伸至行尾的背景色效果?
实现AttributedString背景色延伸至行尾的方案
直接用AttributedString的.backgroundColor属性无法让背景色延伸至视图行尾,这个属性仅作用于文本字符本身的范围,不会填充视图的剩余空白区域。以下是两种可行的解决方案:
方案一:给文本补充空白字符
计算当前文本行剩余的宽度,生成对应数量的空白字符串并拼接到目标文本后,再为整个拼接后的字符串设置背景色。不过这种方法需要适配字体、字号,换行场景下容易出现偏差。示例代码:
// 假设已获取文本视图宽度和当前文本宽度 let textWidth = addedString.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil).width let viewWidth = textView.bounds.width - textView.textContainerInset.left - textView.textContainerInset.right let remainingWidth = viewWidth - textWidth // 根据字体空格宽度计算需要的空格数 let spaceWidth = " ".boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil).width let spaceCount = Int(remainingWidth / spaceWidth) + 1 let paddingString = String(repeating: " ", count: spaceCount) var paddedAddedString = addedString + AttributedString(paddingString) paddedAddedString.mergeAttributes(container) formattedDiff.insert(paddedAddedString, at: formattedDiff.endIndex)方案二:自定义文本视图的绘制逻辑
继承UITextView或UILabel,重写draw(_ rect: CGRect)方法,先绘制对应行的背景色块,再绘制文本。这种方法适配性更强,适合多行、复杂排版场景。示例代码片段:
override func draw(_ rect: CGRect) { // 先绘制自定义背景 guard let layoutManager = layoutManager, let textContainer = textContainer, let attributedText = attributedText else { super.draw(rect) return } attributedText.enumerateAttribute(.backgroundColor, in: NSRange(location: 0, length: attributedText.length), options: []) { value, range, stop in guard let bgColor = value as? UIColor else { return } var glyphRange = NSRange() layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) layoutManager.enumerateLineFragments(forGlyphRange: glyphRange) { rect, _, _, _, _ in // 调整矩形到视图坐标系统,覆盖整行宽度 let lineRect = CGRect( x: textContainerInset.left, y: rect.origin.y + textContainerInset.top, width: bounds.width - textContainerInset.left - textContainerInset.right, height: rect.height ) bgColor.setFill() UIRectFill(lineRect) } } // 再绘制文本 super.draw(rect) }
不建议采用单独添加视图的方式,这种方法需要同步文本滚动、换行、编辑等状态,维护成本高,易出现布局错位。
内容的提问来源于stack exchange,提问作者Guig
相关产品推荐
相关产品推荐

