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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:10:23