如何在CoreGraphics绘制线条的同时于CAShapeLayer上绘制文本?
解决CoreGraphics在CAShapeLayer中同时绘制线条和文本的问题
首先得说,你现在的代码存在几个关键问题,导致线条和文本都没法正常显示:
- 直接在
init()方法里调用draw(at:)完全行不通——此时还没有可用的绘图上下文,而且CAShapeLayer的绘制逻辑是基于它的path属性,不是直接在这里调用文本绘制方法。 - 你创建了箭头的
CGMutablePath,但没把它赋值给layer的path属性,所以线条根本不会被渲染出来。 - 代码末尾的
2 * radiu...明显是笔误,应该是2 * radius。
下面给你两种可行的实现方案:
方案一:用自定义UIView结合CoreGraphics绘制(推荐)
这种方式更直观,把线条和文本的绘制都放在UIView的draw(_:)方法里,借助CoreGraphics上下文完成:
import UIKit class ArrowLineView: UIView { override func draw(_ rect: CGRect) { super.draw(rect) // 1. 绘制箭头线条 guard let context = UIGraphicsGetCurrentContext() else { return } context.setStrokeColor(UIColor.red.cgColor) context.setLineWidth(3) context.setLineCap(.round) context.move(to: CGPoint(x: 100, y: 100)) context.addLine(to: CGPoint(x: 200, y: 100)) // 补充绘制箭头的三角部分 let arrowLength: CGFloat = 10 context.move(to: CGPoint(x: 200, y: 100)) context.addLine(to: CGPoint(x: 200 - arrowLength, y: 100 - arrowLength/2)) context.move(to: CGPoint(x: 200, y: 100)) context.addLine(to: CGPoint(x: 200 - arrowLength, y: 100 + arrowLength/2)) context.strokePath() // 2. 绘制文本 let fontName = "HelveticaNeue-Bold" let font = UIFont(name: fontName, size: 15)! let measurementString = "28 cm" as NSString let textAttributes: [NSAttributedString.Key: Any] = [ .font: font, .foregroundColor: UIColor.black ] measurementString.draw(at: CGPoint(x: 150, y: 100), withAttributes: textAttributes) } }
使用时直接把这个view添加到父视图即可:
let arrowView = ArrowLineView(frame: CGRect(x: 0, y: 0, width: 300, height: 200)) arrowView.backgroundColor = .white view.addSubview(arrowView)
方案二:用CAShapeLayer + CATextLayer组合实现
如果你坚持要用CAShapeLayer绘制线条,可以配合CATextLayer添加文本,让两个图层独立管理:
import UIKit class ArrowLineLayer: CAShapeLayer { private let textLayer = CATextLayer() override init() { super.init() setupTextLayer() } required init?(coder: NSCoder) { super.init(coder: coder) setupTextLayer() } private func setupTextLayer() { textLayer.string = "28 cm" textLayer.font = UIFont(name: "HelveticaNeue-Bold", size: 15) textLayer.fontSize = 15 textLayer.foregroundColor = UIColor.black.cgColor textLayer.frame = CGRect(x: 150, y: 100, width: 50, height: 20) // 可根据文本实际大小调整frame addSublayer(textLayer) } func drawArrow(frame: CGRect) { self.frame = frame lineWidth = 3 strokeColor = UIColor.red.cgColor lineCap = .round let path = CGMutablePath() path.move(to: CGPoint(x: 100, y: 100)) path.addLine(to: CGPoint(x: 200, y: 100)) // 补充箭头三角 let arrowLength: CGFloat = 10 path.move(to: CGPoint(x: 200, y: 100)) path.addLine(to: CGPoint(x: 200 - arrowLength, y: 100 - arrowLength/2)) path.move(to: CGPoint(x: 200, y: 100)) path.addLine(to: CGPoint(x: 200 - arrowLength, y: 100 + arrowLength/2)) self.path = path // 关键:把创建好的路径赋值给layer的path属性 } }
使用方式:
let arrowLayer = ArrowLineLayer() arrowLayer.drawArrow(frame: CGRect(x: 0, y: 0, width: 300, height: 200)) view.layer.addSublayer(arrowLayer)
为什么你的原代码不行?
- CAShapeLayer的
init()只是初始化图层,还没进入绘图流程,没有可用的CGContext,所以调用draw(at:)不会有任何效果。 - 你创建了箭头路径,但没赋值给
self.path,CAShapeLayer根本不知道要绘制什么形状。
希望这些方案能帮到你!
内容的提问来源于stack exchange,提问作者neena
相关产品推荐
相关产品推荐

