Swift Bezier Path在添加Line Method后没有响应

Swift Bezierpath doesnt response after addLine Method

我正在尝试使用 bezierPath 绘制我的视图,我的代码是?

    class auctionCollectionView : UIView{
    let gradient = CAGradientLayer()

    
private var shapeLayer: CALayer?


private func addShape() {
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = mys2().cgPath
    shapeLayer.strokeColor = UIColor.lightGray.cgColor
     
    self.shapeLayer = shapeLayer
    
    let colorTop =  UIColor(hexFromString: "#101820").cgColor
    let colorBottom = UIColor(hexFromString: "#101820").cgColor
    let gradientLayer = CAGradientLayer()
    
    gradientLayer.mask = shapeLayer
    gradientLayer.colors = [colorTop, colorBottom]
    gradientLayer.locations = [0.0, 1.0]
    gradientLayer.frame = mys2().bounds
         
    self.layer.insertSublayer(gradientLayer, at:0)
}
override func draw(_ rect: CGRect) {
    self.addShape()
    
}
func mys2() -> UIBezierPath {
  
    let path = UIBezierPath()

    path.move(to: CGPoint(x: 0, y: self.frame.height/4)) // start top left
    path.addQuadCurve(to:  CGPoint(x: self.frame.width , y:self.frame.height/4), controlPoint: CGPoint(x: self.frame.width/2 , y: 0 ))
    path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height * 3/4))
    
    path.addQuadCurve(to:  CGPoint(x: 0, y: self.frame.height * 3/4), controlPoint: CGPoint(x: self.frame.width/2, y:self.frame.height / 2))
    path.addLine(to: CGPoint(x: 0, y: self.frame.height/4))
    path.close()
    return path
 }
}

输出看起来像

我的第一个 QuadCurve 看起来不错,但是当我尝试将它添加到从 maxX (self.frame.width)maxY ( self.frame.height * 3/4)minX ( 0)maxY (self.frame.height * 3/4)CGPoint(x: self.frame.width/2, y:self.frame.height / 2) 它起作用喜欢加行

我在这里错过了什么?此致!

你的路径似乎没问题,但我担心你的问题是你在覆盖 draw 方法时调用的内容。

您应该先添加图层,然后再管理它们。或者您应该使用 draw rect 来绘制所有内容而不使用图层。在这种情况下,我建议使用第二个。我不太确定你的完整实现应该如何,但从复制你的路径并查看渐变代码来看,它可能与此类似:

@IBDesignable class DrawingView: UIView {
    
    @IBInspectable var topColor: UIColor? = .red
    @IBInspectable var bottomColor: UIColor? = .blue

    private func mys2() -> UIBezierPath {
      
        let path = UIBezierPath()

        path.move(to: CGPoint(x: 0, y: self.frame.height/4)) // start top left
        path.addQuadCurve(to:  CGPoint(x: self.frame.width , y:self.frame.height/4), controlPoint: CGPoint(x: self.frame.width/2 , y: 0 ))
        path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height * 3/4))
        
        path.addQuadCurve(to:  CGPoint(x: 0, y: self.frame.height * 3/4), controlPoint: CGPoint(x: self.frame.width/2, y:self.frame.height / 2))
        path.addLine(to: CGPoint(x: 0, y: self.frame.height/4))
        path.close()
        return path
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        guard let context = UIGraphicsGetCurrentContext(), let topColor = topColor, let bottomColor = bottomColor else {
            return
        }
        
        // Save because of clipping
        context.saveGState()
        
        // Add clipping from my path
        mys2().addClip()
        
        let locations: [CGFloat] = [0.0, 1.0]
        let colors = [topColor.cgColor, bottomColor.cgColor]
        if let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: locations) {
            context.drawLinearGradient(gradient, start: CGPoint.zero, end: CGPoint(x: 0.0, y: frame.size.height), options: CGGradientDrawingOptions(rawValue: 0))
        }
        
        context.restoreGState()
        
        
    }
    
}

所以我们可以只使用裁剪来代替蒙版,这就是蒙版在图层中首先所做的事情。梯度代码有点不同,但仍然足够相似。

现在请注意,只要视图需要重绘,就会调用此方法。要强制重绘,您需要调用 setNeedsDisplay。所以像下面这样的东西可能很常见:

@IBInspectable var topColor: UIColor? = .red { didSet { refresh() } }
@IBInspectable var bottomColor: UIColor? = .blue { didSet { refresh() } }

override var frame: CGRect { didSet { refresh() } }

override func layoutSubviews() {
    super.layoutSubviews()
    refresh()
}

private func refresh() { setNeedsDisplay() }

所以基本上你强制它重绘时:

  • 任何颜色变化
  • 正在设置框架(通常情况下不使用 auto-layout)
  • 正在布局子视图(使用 auto-layout 时的通常情况)

注意调用setNeedsDisplay不会强制立即重载,调用draw方法。它只是将组件标记为脏,并会在下一个循环中重绘它。结果是,即使在同一个循环(堆栈、方法...)中多次调用 setNeedsDisplaydraw 也只会被调用一次。所以没有性能问题。

在您的情况下,使用图层也可以完成同样的操作。每当发生变化时,您都需要一个 refresh 方法。那么这个方法应该创建子层或更正子层框架,掩码...并且应该删除 draw 方法。因此,要么使用一种方法,要么使用另一种方法,但不能同时使用这两种方法。