如何获取代码创建的UIView的Core Graphics上下文并内联绘制?
问题解答
核心结论:不能直接在viewDidLoad中获取UIView的上下文并绘制
iOS中UIView的绘图上下文并不是随时都能获取的——只有当系统触发视图绘制流程时(比如视图首次显示、调用setNeedsDisplay()触发重绘后),才会创建临时的绘图上下文,再调用draw(_:)方法让你在这个上下文里绘制内容。在viewDidLoad阶段,视图还没进入绘制流程,根本不存在可用的绘图上下文,所以没法直接拿它来画路径。
关于draw(_:)方法的误区
UIView的draw(_:)方法不是返回图像,它的作用是:系统在需要渲染视图时,会创建一个关联到视图图层的绘图上下文,然后调用这个方法,你在方法里通过UIGraphicsGetCurrentContext()拿到这个上下文,执行绘制指令,最后系统会把上下文里的内容渲染到视图的图层上,后续视图显示的就是这个图层的缓存内容。
而UIGraphicsImageRenderer是独立的绘图机制:它创建一个专属的绘图上下文,你在闭包里绘制的内容会被转换成UIImage,这个图像可以给UIImageView使用或者保存,但和UIView的图层没有直接关联。
正确实现方式
有两种常用方案,推荐第二种(性能更优):
方案1:自定义UIView子类重写draw(_:)
class PathView: UIView { var path: UIBezierPath? { didSet { setNeedsDisplay() // 路径变化时触发重绘 } } override func draw(_ rect: CGRect) { super.draw(rect) guard let path = path else { return } UIColor.red.setStroke() // 设置描边颜色 path.lineWidth = 2 path.stroke() // 绘制路径 } } // 在ViewController中使用 class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let path = getPath() // 你的UIBezierPath获取方法 let myView = PathView() myView.path = path myView.frame = CGRect(x: 96, y: 48, width: 64, height: 256) view.addSubview(myView) } }
方案2:使用CAShapeLayer(推荐)
这种方式不需要重写draw(_:),直接把路径赋值给图层,性能更好(图层渲染由GPU处理,比CPU绘制的Core Graphics更高效):
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let path = getPath() // 你的UIBezierPath获取方法 let myView = UIView() myView.frame = CGRect(x: 96, y: 48, width: 64, height: 256) let shapeLayer = CAShapeLayer() shapeLayer.path = path.cgPath shapeLayer.strokeColor = UIColor.red.cgColor shapeLayer.lineWidth = 2 shapeLayer.fillColor = UIColor.clear.cgColor // 不需要填充就设为透明 myView.layer.addSublayer(shapeLayer) view.addSubview(myView) } }
你可能存在的理解误区(来自JS背景)
在JavaScript的Canvas API中,你可以随时获取canvas元素的上下文,主动调用绘制方法,这是因为浏览器的Canvas是即时绘制模式。但iOS的UIView采用的是被动绘制+图层缓存的机制:
- 视图的绘制由系统主动触发,而非开发者主动调用
- 绘制内容会被缓存到图层,只有当视图需要更新时才会重绘
- 不能在系统的绘制流程之外获取视图的绘图上下文进行绘制
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

