iOS中CGPath转SVG异常:文本转路径后显示为圆形而非文字
iOS文本转CGPath再转SVG后显示为圆形的问题修复
问题根源分析
你的代码存在两个核心错误,导致SVG渲染异常:
- 贝塞尔曲线点处理错误:
pathToSVG函数中处理二次/三次曲线时,重复使用同一个点,未正确提取所有控制点和终点。 - SVG坐标适配缺失:仅翻转路径Y轴不足以匹配SVG坐标系统,需要通过
viewBox修正路径的偏移问题。
修复后的代码实现
1. 修正pathToSVG的曲线点解析逻辑
func pathToSVG(path: CGPath, color: UIColor) -> String { let boundingBox = path.boundingBox // 添加viewBox参数,确保SVG能正确识别路径的完整坐标范围 let viewBox = "\(boundingBox.minX) \(boundingBox.minY) \(boundingBox.width) \(boundingBox.height)" var svgString = "<svg width=\"\(boundingBox.width)\" height=\"\(boundingBox.height)\" viewBox=\"\(viewBox)\" xmlns=\"http://www.w3.org/2000/svg\">\n" svgString += "<path d=\"" path.applyWithBlock { elementPointer in let element = elementPointer.pointee let points = element.points switch element.type { case .moveToPoint: svgString += "M \(points.pointee.x) \(points.pointee.y) " case .addLineToPoint: svgString += "L \(points.pointee.x) \(points.pointee.y) " case .addQuadCurveToPoint: // 二次曲线:控制点(points[0]) + 终点(points[1]) let controlPoint = points[0] let endPoint = points[1] svgString += "Q \(controlPoint.x) \(controlPoint.y) \(endPoint.x) \(endPoint.y) " case .addCurveToPoint: // 三次曲线:控制点1(points[0]) + 控制点2(points[1]) + 终点(points[2]) let controlPoint1 = points[0] let controlPoint2 = points[1] let endPoint = points[2] svgString += "C \(controlPoint1.x) \(controlPoint1.y) \(controlPoint2.x) \(controlPoint2.y) \(endPoint.x) \(endPoint.y) " case .closeSubpath: svgString += "Z " @unknown default: break } } svgString += "\" fill=\"\(color.hexString)\" />\n" svgString += "</svg>" return svgString }
2. 优化textToPath的同步逻辑
移除不必要的延迟赋值,避免返回路径与全局变量不同步:
func textToPath(text: String, font: UIFont) -> CGPath? { let attributedString = NSAttributedString(string: text, attributes: [.font: font]) let line = CTLineCreateWithAttributedString(attributedString) let runArray = CTLineGetGlyphRuns(line) as NSArray let path = CGMutablePath() for run in runArray { let run = run as! CTRun let count = CTRunGetGlyphCount(run) for index in 0..<count { let range = CFRangeMake(index, 1) var glyph: CGGlyph = 0 var position: CGPoint = .zero CTRunGetGlyphs(run, range, &glyph) CTRunGetPositions(run, range, &position) if let glyphPath = CTFontCreatePathForGlyph(font, glyph, nil) { var transform = CGAffineTransform(translationX: position.x, y: position.y) transform = transform.scaledBy(x: 1, y: -1) // 适配SVG Y轴方向 path.addPath(glyphPath, transform: transform) } } } cgPath = path // 直接同步赋值 return path }
额外注意事项
- 确保
UIColor的hexString扩展返回标准SVG颜色格式(如#RRGGBB或#RRGGBBAA)。 - 若仍存在位置偏移,可打印
boundingBox的数值,确认viewBox参数是否完整覆盖路径范围。
内容的提问来源于stack exchange,提问作者HeWhoRemains
相关产品推荐
相关产品推荐

