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

Swift中使用NSAttributedString无法绘制圆角描边的问题求助

Swift实现文本圆角描边方案

NSMutableAttributedString没有直接提供圆角描边的属性键,系统默认的strokeWidth和strokeColor是基于字体原始字形路径绘制,无法生成圆角效果。要实现圆角描边,需要通过自定义绘制文本路径并添加圆角处理来完成,以下是一种可行的实现方式:

自定义UILabel子类实现圆角描边

创建继承自UILabel的子类,重写draw(_ rect: CGRect)方法,借助CoreText获取文本字形路径,通过设置路径的圆角连接属性实现圆角描边:

import UIKit

class RoundedStrokeLabel: UILabel {
    /// 描边宽度
    var strokeWidth: CGFloat = 2.0
    /// 描边颜色
    var strokeColor: UIColor = .black
    
    override func draw(_ rect: CGRect) {
        guard let text = text, let font = font else { return }
        
        // 构建带字体属性的富文本
        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(.font, value: font, range: NSRange(location: 0, length: text.count))
        
        // 初始化CoreText排版相关对象
        let framesetter = CTFramesetterCreateWithAttributedString(attributedString as CFAttributedString)
        let textPath = CGPath(rect: bounds, transform: nil)
        let textFrame = CTFramesetterCreateFrame(framesetter, CFRange(location: 0, length: attributedString.length), textPath, nil)
        
        let context = UIGraphicsGetCurrentContext()
        context?.saveGState()
        // 转换坐标系适配UIKit
        context?.translateBy(x: 0, y: bounds.height)
        context?.scaleBy(x: 1.0, y: -1.0)
        
        // 获取文本行与行原点
        let lines = CTFrameGetLines(textFrame) as [CTLine]
        var lineOrigins = [CGPoint](repeating: .zero, count: lines.count)
        CTFrameGetLineOrigins(textFrame, CFRange(location: 0, length: 0), &lineOrigins)
        
        // 遍历每行处理字形路径
        for (lineIndex, line) in lines.enumerated() {
            let runs = CTLineGetGlyphRuns(line) as [CTRun]
            for run in runs {
                let runFont = CTRunGetAttributes(run)[kCTFontAttributeName] as! CTFont
                let glyphCount = CTRunGetGlyphCount(run)
                
                var glyphs = [CGGlyph](repeating: 0, count: glyphCount)
                var positions = [CGPoint](repeating: .zero, count: glyphCount)
                
                CTRunGetGlyphs(run, CFRange(location: 0, length: 0), &glyphs)
                CTRunGetPositions(run, CFRange(location: 0, length: 0), &positions)
                
                // 处理每个字形的圆角描边
                for glyphIndex in 0..<glyphCount {
                    let glyph = glyphs[glyphIndex]
                    var position = positions[glyphIndex]
                    position.y += lineOrigins[lineIndex].y
                    
                    guard let glyphPath = CTFontCreatePathForGlyph(runFont, glyph, nil) else { continue }
                    // 转换字形路径到当前排版位置
                    let transformedPath = glyphPath.copy(transform: CGAffineTransform(translationX: position.x, y: position.y))
                    // 生成带圆角连接的描边路径
                    let roundedStrokePath = transformedPath.copy(
                        strokingWithWidth: strokeWidth,
                        lineCap: .round,
                        lineJoin: .round,
                        miterLimit: 0
                    )
                    
                    // 绘制圆角描边
                    strokeColor.setStroke()
                    context?.addPath(roundedStrokePath)
                    context?.setLineWidth(strokeWidth)
                    context?.drawPath(using: .stroke)
                }
            }
        }
        
        context?.restoreGState()
        
        // 绘制内部填充文本
        super.draw(rect)
    }
}

使用示例

直接实例化自定义子类并设置属性:

let roundedLabel = RoundedStrokeLabel()
roundedLabel.text = "Swift圆角描边"
roundedLabel.font = UIFont.systemFont(ofSize: 32, weight: .bold)
roundedLabel.strokeWidth = 3.0
roundedLabel.strokeColor = .systemBlue
roundedLabel.textColor = .white
roundedLabel.frame = CGRect(x: 40, y: 150, width: 300, height: 80)
view.addSubview(roundedLabel)

关键说明

  • 核心是通过CGPath.copy(strokingWithWidth:lineCap:lineJoin:miterLimit:)方法,将lineJoin设置为.round,让路径转角处呈现圆角
  • 借助CoreText可以精准获取每个字形的路径,确保所有文本转角都能应用圆角处理
  • 这种方式相比系统默认描边,能完全控制描边的圆角效果,适配所有字体

内容的提问来源于stack exchange,提问作者Jabed Dhali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 04:00:21