如何自定义NSAttributedString的下划线?含颜色、宽度等多维度需求
自定义NSAttributedString下划线的实现方案
当然可以!NSAttributedString本身就支持不少下划线的自定义配置,要是你有更复杂的需求(比如用自定义视图当下划线),咱们也有靠谱的实现方案。我来一步步给你拆解:
一、基础自定义:下划线颜色、宽度、间距
针对颜色、宽度、文本与下划线间距这些基础需求,用NSAttributedString的原生属性就能搞定,不同iOS版本的支持情况略有区别:
- 下划线颜色:通过
NSUnderlineColorAttributeName设置,直接传入UIColor即可,全iOS版本支持。 - 下划线宽度:iOS 15+可以用
NSUnderlineThicknessAttributeName直接设置厚度值;iOS 15以下的话,只能通过NSUnderlineStyle的thick枚举(比默认粗一点),或者用后面的高级方案自定义。 - 文本与下划线的间距:iOS 13+可以用
NSUnderlineOffsetAttributeName设置偏移量(正数表示下划线向下偏移,增大与文本的距离);低版本同样需要用高级方案处理。
Swift代码示例(iOS 13+)
let mutableAttrStr = NSMutableAttributedString(string: "这是自定义下划线的示例文本") // 配置下划线属性 let underlineAttrs: [NSAttributedString.Key: Any] = [ .underlineStyle: NSUnderlineStyle.solid.rawValue, // 实线样式 .underlineColor: UIColor.systemRed, // 下划线颜色 .underlineThickness: 2.0, // 下划线宽度(iOS15+) .underlineOffset: 3.0 // 与文本的间距(iOS13+,正数向下偏移) ] // 给整个文本添加属性 mutableAttrStr.addAttributes(underlineAttrs, range: NSRange(location: 0, length: mutableAttrStr.length)) // 赋值给Label或TextView let label = UILabel() label.attributedText = mutableAttrStr label.sizeToFit()
二、高级需求:自定义视图作为下划线
如果要实现更复杂的效果(比如渐变下划线、圆角下划线、带图标的下划线),原生属性就不够用了,这里有两种常用方案:
方案1:通过TextKit自定义绘制
利用NSLayoutManager的回调,接管下划线的绘制逻辑,自己绘制自定义图形或视图。这种方案适合动态文本(比如UITextView中的可编辑文本)。
自定义LayoutManager示例
class CustomUnderlineLayoutManager: NSLayoutManager { override func drawUnderline(forGlyphRange glyphRange: NSRange, underlineType underlineVal: NSUnderlineStyle, baselineOffset: CGFloat, lineFragmentRect: CGRect, lineFragmentGlyphRange: NSRange, container: NSTextContainer) { // 跳过系统默认的下划线绘制,改用自定义逻辑 let characterRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil) guard let textStorage = self.textStorage else { return } // 计算自定义下划线的位置和尺寸 let underlineY = lineFragmentRect.origin.y + baselineOffset + 3 // 调整与文本的间距 let underlineRect = CGRect(x: lineFragmentRect.origin.x, y: underlineY, width: lineFragmentRect.width, height: 2.5) // 绘制渐变圆角下划线(你可以换成任何自定义图形/视图) let gradientLayer = CAGradientLayer() gradientLayer.frame = underlineRect gradientLayer.colors = [UIColor.systemBlue.cgColor, UIColor.systemPurple.cgColor] gradientLayer.cornerRadius = underlineRect.height / 2 // 将layer渲染到当前绘图上下文 UIGraphicsGetCurrentContext()?.saveGState() gradientLayer.render(in: UIGraphicsGetCurrentContext()!) UIGraphicsGetCurrentContext()?.restoreGState() } } // 使用方式:替换TextView的LayoutManager let textView = UITextView(frame: CGRect(x: 20, y: 100, width: 300, height: 50)) let customLayoutManager = CustomUnderlineLayoutManager() let textStorage = NSTextStorage(attributedString: mutableAttrStr) let textContainer = NSTextContainer(size: textView.bounds.size) customLayoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(customLayoutManager) textView.layoutManager = customLayoutManager textView.textContainer = textContainer
方案2:叠加UIView到文本下方
如果是静态文本(比如UILabel),可以直接计算文本的位置,然后在下方添加自定义UIView。这种方案更简单直观。
代码示例
let label = UILabel(frame: CGRect(x: 20, y: 100, width: 300, height: 30)) label.text = "带自定义视图下划线的静态文本" label.font = UIFont.systemFont(ofSize: 16) label.sizeToFit() // 计算下划线视图的位置 let underlineY = label.frame.maxY + 2 // 与文本的间距 let underlineFrame = CGRect(x: label.frame.minX, y: underlineY, width: label.frame.width, height: 3) // 创建自定义下划线视图(比如带圆角的纯色视图) let underlineView = UIView(frame: underlineFrame) underlineView.backgroundColor = UIColor.systemGreen underlineView.layer.cornerRadius = 1.5 // 添加到父视图 view.addSubview(label) view.addSubview(underlineView)
内容的提问来源于stack exchange,提问作者Luda
相关产品推荐
相关产品推荐

