2017-08-28 69 views
1

enter image description here畫上一個UIBezierPath

上面的照片徑向背景顯示瞭如何將以下代碼運行:

extension Int { 
    var degreesToRadians: Double { return Double(self) * .pi/180 } 
    var radiansToDegrees: Double { return Double(self) * 180/.pi } 
} 
extension FloatingPoint { 
    var degreesToRadians: Self { return self * .pi/180 } 
    var radiansToDegrees: Self { return self * 180/.pi } 
} 


class SunBurstView: UIView { 
    override func draw(_ rect: CGRect) { 
     let radius: CGFloat = rect.size.width/2 
     UIColor.yellow.setFill() 
     let bezierPath = UIBezierPath() 
     let centerPoint = CGPoint(x: rect.origin.x + radius, y: rect.size.height/2) 
     var thisPoint = CGPoint(x: centerPoint.x + radius, y: centerPoint.y + radius) 
     bezierPath.move(to: centerPoint) 
     var thisAngle: CGFloat = 0.0 
     let sliceDegrees: CGFloat = 360.0/20/2.0 
     for _ in 0..<20 { 
      let x = radius * CGFloat(cosf(Float((thisAngle + sliceDegrees).degreesToRadians))) + centerPoint.x 
      let y = radius * CGFloat(sinf(Float((thisAngle + sliceDegrees).degreesToRadians))) + centerPoint.y 
      thisPoint = CGPoint(x: x, y: y) 
      bezierPath.addLine(to: thisPoint) 
      thisAngle += sliceDegrees 
      let x2 = radius * CGFloat(cosf(Float((thisAngle + sliceDegrees).degreesToRadians))) + centerPoint.x 
      let y2 = radius * CGFloat(sinf(Float((thisAngle + sliceDegrees).degreesToRadians))) + centerPoint.y 
      thisPoint = CGPoint(x: x2, y: y2) 
      bezierPath.addLine(to: thisPoint) 
      bezierPath.addLine(to: centerPoint) 
      thisAngle += sliceDegrees 
     } 
     bezierPath.close() 
     bezierPath.lineWidth = 0 

     let colors = [UIColor.green.cgColor, UIColor.blue.cgColor] as CFArray 
     let gradient = CGGradient(colorsSpace: nil, colors: colors, locations: nil) 
     let endPosition = min(frame.width, frame.height)/2 
     let center = CGPoint(x: bounds.size.width/2, y: bounds.size.height/2) 
     UIGraphicsGetCurrentContext()?.drawRadialGradient(gradient!, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: endPosition, options: .drawsAfterEndLocation) 

     bezierPath.fill() 
     bezierPath.stroke() 
    } 
} 

我想,徑向背景只填充UIBezierPath。通常這可以通過遮罩層完成,但是漸變沒有屬性遮罩。任何有關如何僅在UIBezierPath上繪製漸變徑向背景的幫助,我們感激不盡!它應該在沒有UIBezierPath的UIView上透明。

的線性梯度(複製粘貼將工作)全碼:

class SunBurstView: UIView { 
    override func draw(_ rect: CGRect) { 
     let radius: CGFloat = rect.size.width/2 
     UIColor.yellow.setFill() 
     let bezierPath = UIBezierPath() 
     let centerPoint = CGPoint(x: rect.origin.x + radius, y: rect.size.height/2) 
     var thisPoint = CGPoint(x: centerPoint.x + radius, y: centerPoint.y + radius) 
     bezierPath.move(to: centerPoint) 
     var thisAngle: CGFloat = 0.0 
     let sliceDegrees: CGFloat = 360.0/20/2.0 
     for _ in 0..<20 { 
      let x = radius * CGFloat(cosf(Float((thisAngle + sliceDegrees).degreesToRadians))) + centerPoint.x 
      let y = radius * CGFloat(sinf(Float((thisAngle + sliceDegrees).degreesToRadians))) + centerPoint.y 
      thisPoint = CGPoint(x: x, y: y) 
      bezierPath.addLine(to: thisPoint) 
      thisAngle += sliceDegrees 
      let x2 = radius * CGFloat(cosf(Float((thisAngle + sliceDegrees).degreesToRadians))) + centerPoint.x 
      let y2 = radius * CGFloat(sinf(Float((thisAngle + sliceDegrees).degreesToRadians))) + centerPoint.y 
      thisPoint = CGPoint(x: x2, y: y2) 
      bezierPath.addLine(to: thisPoint) 
      bezierPath.addLine(to: centerPoint) 
      thisAngle += sliceDegrees 
     } 
     bezierPath.close() 
//  let colors = [UIColor.green.cgColor, UIColor.blue.cgColor] as CFArray 
//  let gradient = CGGradient(colorsSpace: nil, colors: colors, locations: nil) 
//  let endPosition = min(frame.width, frame.height)/2 
//  let center = CGPoint(x: bounds.size.width/2, y: bounds.size.height/2) 
//  UIGraphicsGetCurrentContext()?.drawRadialGradient(gradient!, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: endPosition, options: .drawsAfterEndLocation) 


     //linear 
     let shape = CAShapeLayer() 
     shape.path = bezierPath.cgPath 
     shape.lineWidth = 0.0 
     shape.strokeColor = UIColor.black.cgColor 
     self.layer.addSublayer(shape) 

     let gradient = CAGradientLayer() 
     gradient.frame = bezierPath.bounds 
     gradient.colors = [UIColor.blue.cgColor, UIColor.green.cgColor] 

     let shapeMask = CAShapeLayer() 
     shapeMask.path = bezierPath.cgPath 
     gradient.mask = shapeMask 

     self.layer.addSublayer(gradient) 


     bezierPath.lineWidth = 0 
     bezierPath.fill() 
     bezierPath.stroke() 
    } 
} 
+0

一種方法:創建一個漸變圖層,然後使用該路徑作爲圖層蒙版。很多例子在那裏...只要搜索'UIBezierPath漸變填充',你應該在你的路上。 – DonMag

+0

@DonMag是的,我知道面膜層,我說在我的問題。但是,漸變沒有屬性遮罩。當創建一個新的漸變圖層時,我該如何創建一個圓形漸變? –

+0

您是否可以用線性漸變填充您的SunBurst路徑? – DonMag

回答

1

這裏是你如何讓你的原代碼工作,最小的變化。

override func draw(_ rect: CGRect) { 
    // [...] 
    // your code untouched until this line: 
    bezierPath.close() 

    // change the rest of the function to: 
    bezierPath.fill() 

    UIGraphicsGetCurrentContext()!.setBlendMode(.sourceIn) 
    let colors = [UIColor.green.cgColor, UIColor.blue.cgColor] as CFArray 
    let gradient = CGGradient(colorsSpace: nil, colors: colors, locations: nil) 
    let endPosition = min(frame.width, frame.height)/2 
    let center = CGPoint(x: bounds.size.width/2, y: bounds.size.height/2) 
    UIGraphicsGetCurrentContext()?.drawRadialGradient(gradient!, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: endPosition, options: .drawsAfterEndLocation) 
} 

結果:

Result

的想法是第一與射線繪製貝塞爾。這裏的顏色並不重要,這只是繪製阿爾法。

然後,我們使用Quartz特有的混合模式之一在alpha的頂部繪製漸變:kCGBlendModeSourceIn(請參閱Porter-Duff alpha compositing)。

此模式在現有alpha的頂部繪製任何東西,只替換像素的顏色,保持alpha原樣。這基本上就像使用當前圖形的alpha作爲掩碼。

1

這裏是一個徑向漸變層的一種實現方式:

class RadialGradientLayer: CALayer { 

    var center: CGPoint { 
     return CGPoint(x: bounds.width/2, y: bounds.height/2) 
    } 

    var radius: CGFloat { 
     return min(bounds.width/2.0, bounds.height/2.0) 
    } 

    var colors: [UIColor] = [UIColor.black, UIColor.lightGray] { 
     didSet { 
      setNeedsDisplay() 
     } 
    } 

    var cgColors: [CGColor] { 
     return colors.map({ (color) -> CGColor in 
      return color.cgColor 
     }) 
    } 

    override init() { 
     super.init() 
     needsDisplayOnBoundsChange = true 
    } 

    required init(coder aDecoder: NSCoder) { 
     super.init() 
    } 

    override func draw(in ctx: CGContext) { 
     ctx.saveGState() 
     let colorSpace = CGColorSpaceCreateDeviceRGB() 
     guard let gradient = CGGradient(colorsSpace: colorSpace, colors: cgColors as CFArray, locations: nil) else { 
      return 
     } 
     ctx.drawRadialGradient(gradient, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: radius, options: CGGradientDrawingOptions(rawValue: 0)) 
    } 

} 

因此,在你最新的代碼,更換:

let gradient = CAGradientLayer() 
    gradient.frame = bezierPath.bounds 
    gradient.colors = [UIColor.blue.cgColor, UIColor.green.cgColor] 

有:

let gradient = RadialGradientLayer() 
    gradient.frame = bezierPath.bounds 
    gradient.colors = [UIColor.blue, UIColor.green] 

,導致:

enter image description here