Ios 绘图(rect:CGRect)未在自定义视图中调用

Ios 绘图(rect:CGRect)未在自定义视图中调用,ios,swift,Ios,Swift,我试图通过扩展UIView类来创建自定义视图,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 minLengt

我试图通过扩展UIView类来创建自定义视图,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)
    }
当调用init方法时,它还没有被设置,并且它总是画一个灰色的圆圈

请帮助我了解未调用draw方法的原因


提前感谢

我不确定您的根本错误在哪里,但您不应该覆盖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()
}
如果确实要覆盖drawrect:,则根本不需要创建图层或覆盖初始值设定项:

@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()
}

顺便说一下,您可以使用let minLength=minbounds.width,bounds.height,如果degressToRadians实现正确,那么使用CGFloat360.DegreesToradians就足够了。注意,在draw中添加子层不是一个好主意。子层只能添加一次,而不是每次重新渲染时。还请注意,您必须在需要时更新层的框架。还请注意,您应该始终实现所有指定的初始值设定项,而不仅仅是initcoder:,initframe:也必须实现。@Sulthan point注意到。也会发生同样的变化。谢谢你的建议。不过,我的问题是,调用重写的draw方法的最低标准是什么。我遗漏了什么吗?每次需要重新提交组件时,即调用setNeedsDisplay时,都应该调用重写的方法。它应该至少被调用一次。奇怪的是,它根本没有被调用。当然,视图必须被添加到superview中,并且具有非零大小。
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()
}
@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()
}