我正在尝试通过扩展类UIView来创建自定义视图,该类可以在自定义视图的中心显示一个圆圈。 为了添加自定义绘图,我重写了draw(_ rect:CGRect)方法,如下所示。
public override func draw(_ rect: CGRect) {
super.draw(rect)
let center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
let minLength = bounds.width <= bounds.height ? bounds.width : bounds.height
let circlePath = UIBezierPath (arcCenter: center, radius: CGFloat(minLength / 2), startAngle: 0, endAngle: CGFloat(Float(360).degreesToRadians) , clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = circleColor.cgColor
layer.addSublayer(shapeLayer)
}
但是当我尝试在storyboard中添加相同的自定义组件并在draw方法中添加断点时,它没有被调用。为了好奇,我在init中添加了一个断点?(编码器aDecoder:NSCoder)方法被调用。此外,当我尝试覆盖下面的方法时,它工作正常。
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
drawCircle()
}
fileprivate func drawCircle() {
let center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
let minLength = bounds.width <= bounds.height ? bounds.width : bounds.height
let circlePath = UIBezierPath (arcCenter: center, radius: CGFloat(minLength / 2), startAngle: 0, endAngle: CGFloat(Float(360).degreesToRadians) , clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = circleColor.cgColor
layer.addSublayer(shapeLayer)
}
方法的问题是我有一个自定义属性circleColor
@IBInspectable
public var circleColor : UIColor = UIColor.gray
调用init方法时尚未设置的,它总是绘制一个灰色圆圈。
请帮助告诉我没有调用draw方法的原因。
提前致谢
答案 0 :(得分:2)
我不确定你的根本错误在哪里,但你不应该只是添加一个图层来覆盖draw(:)
。这意味着每次组件重新渲染时都会再次添加新图层。那不是你想要的。
更改颜色属性时,还应确保更新图层颜色。为此,只需保存对图层的引用:
private let shapeLayer = CAShapeLayer()
@IBInspectable
public var circleColor : UIColor = UIColor.gray {
didSet {
shapeLayer.fillColor = circleColor.cgColor
}
}
public override init(frame: CGRect = .zero) {
super.init(frame: frame)
updateLayer()
layer.addSublayer(shapeLayer)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
updateLayer()
layer.addSublayer(shapeLayer)
}
fileprivate func updateLayer() {
let center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
let minLength = min(bounds.width, bounds.height)
let circlePath = UIBezierPath(arcCenter: center, radius: minLength / 2, startAngle: 0, endAngle: CGFloat(Float(360).degreesToRadians), clockwise: true)
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = circleColor.cgColor
}
override func layoutSubviews() {
super.layoutSubviews()
// update layer position
updateLayer()
}
如果您真的想要覆盖draw(rect:)
,则根本不需要创建图层或覆盖初始值设定项:
@IBInspectable
public var circleColor : UIColor = UIColor.gray {
didSet {
setNeedsDisplay()
}
}
public override func draw(_ rect: CGRect) {
// no need to call super.draw(rect)
let center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
let minLength = min(bounds.width, bounds.height)
let circlePath = UIBezierPath(arcCenter: center, radius: minLength / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true)
// the following methods use current CGContext
circleColor.set()
circlePath.fill()
}