自定义UIView中draw(_ rect: CGRect)方法未被调用的问题
我来帮你梳理下这个问题的排查方向,毕竟Storyboard里自定义视图的draw(_:)方法不触发是个挺常见的坑😉
常见排查步骤
以下是按优先级排序的排查点,你可以逐一验证:
检查是否调用了
setNeedsDisplay()
系统不会自动在init?(coder:)完成后触发绘制,如果你在初始化时没有通知视图需要重绘,draw(_:)就不会被调用。在init?(coder:)方法末尾加上self.setNeedsDisplay(),强制系统触发绘制流程。这很可能是你“另一种写法能工作”的核心原因——另一种写法里大概率加了这个调用。验证
draw(_:)方法签名是否完全正确
确保方法签名没有拼写错误,且带有override关键字,正确格式应该是:override func draw(_ rect: CGRect) { // 你的绘制逻辑 }要是漏掉
override、参数名写错(比如把rect写成frame),系统会把它当成普通方法,不会自动调用。检查
isOpaque属性设置
如果你的视图设置了isOpaque = true,但draw(_:)里没有完全填充整个rect区域,系统可能会跳过绘制。可以尝试把isOpaque设为false,或者确保绘制代码覆盖了整个视图范围。确认Storyboard视图的类关联是否正确
虽然init?(coder:)能触发,但还是要再核对一遍:选中Storyboard里的目标视图,在Identity Inspector的Class字段是否准确填写了你的自定义视图类名,Module选项有没有选对(尤其是多Target或使用CocoaPods的场景)。检查
layoutSubviews()的重写逻辑
如果你重写了layoutSubviews()但忘记调用super.layoutSubviews(),会打乱视图的布局与绘制流程。确保自定义的layoutSubviews()里第一行就是super.layoutSubviews()。代码中手动实例化测试
在ViewController的viewDidLoad里手动创建一个你的自定义视图实例并添加到界面上:let circleView = CircleView(frame: CGRect(x: 100, y: 100, width: 100, height: 100)) view.addSubview(circleView)如果这样
draw(_:)能触发,说明问题出在Storyboard的配置上;如果还是不触发,那就是自定义视图本身的逻辑问题。
参考正确实现示例
这里给你一个能正常工作的自定义圆形视图代码,你可以对照调整:
import UIKit class CircleView: UIView { override init(frame: CGRect) { super.init(frame: frame) commonSetup() } required init?(coder: NSCoder) { super.init(coder: coder) commonSetup() } private func commonSetup() { backgroundColor = .clear isOpaque = false setNeedsDisplay() // 强制触发绘制 } override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } // 绘制中心圆形 let center = CGPoint(x: rect.midX, y: rect.midY) let radius = min(rect.width, rect.height) / 2 - 5 context.setStrokeColor(UIColor.systemBlue.cgColor) context.setLineWidth(3) context.addArc(center: center, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true) context.strokePath() } }
内容的提问来源于stack exchange,提问作者Suneet Agrawal

