You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:34:46