swift 如何在NSView上绘制渐变色边框?

c9qzyr3d  于 2023-04-28  发布在  Swift
关注(0)|答案(1)|浏览(224)

我花了几个小时在NSView上画一个渐变边框,like this
我已经调整到NSView的代码:

class BlurView: NSView {
  
  override init(frame: CGRect) {
    super.init(frame: frame)

    let gradient = CAGradientLayer()
    gradient.frame =  CGRect(origin: CGPoint.zero, size: frame.size)
    gradient.colors = [NSColor.blue.cgColor, NSColor.green.cgColor, NSColor.blue.cgColor]

    let shape = CAShapeLayer()
    shape.lineWidth = 2
    shape.path = NSBezierPath(rect: self.bounds).cgPath
    shape.strokeColor = NSColor.black.cgColor
    shape.fillColor = NSColor.clear.cgColor
    gradient.mask = shape
    
    self.wantsLayer = true
    self.layer?.insertSublayer(gradient, at: 0)
  }
}

但是它不起作用,我不能在网上找到更多的信息,所以也许这只适用于iOS。有几件有趣的事:

  • self.bounds打印(0.0,0. 0,0. 0,0.0)所以我不认为这是正确的工作
  • 我使用以下代码添加了cgPath作为NSBeziertPath的扩展
import Foundation

extension NSBezierPath {

    public var cgPath: CGPath {
        let path = CGMutablePath()
        var points = [CGPoint](repeating: .zero, count: 3)

        for i in 0 ..< elementCount {
            let type = element(at: i, associatedPoints: &points)
            switch type {
            case .moveTo:
                path.move(to: points[0])
            case .lineTo:
                path.addLine(to: points[0])
            case .curveTo:
                path.addCurve(to: points[2], control1: points[0], control2: points[1])
            case .closePath:
                path.closeSubpath()
            @unknown default:
                continue
            }
        }

        return path
    }
}

你知道怎么让它工作吗?

qltillow

qltillow1#

我把它修好了。问题不在于我如何渲染边界,而在于如何管理视图。这是一个嵌入在react-native中的组件,因此它被初始化为0大小,并且只在以后更新。因此,渲染边框的回调需要在update方法中:

import Cocoa

let blue = CGColor(red: 0, green: 98.0/255.0, blue: 255.0/255.0, alpha: 0.2)
let blue2 = CGColor(red: 0, green: 98.0/255.0, blue: 255.0/255.0, alpha: 0.1)
let green = CGColor(red: 63.0/255.0, green: 255.0/255.0, blue: 128.0/255.0, alpha: 0.2)
let blueBg1 = CGColor(red: 0, green: 98.0/255.0, blue: 255.0/255.0, alpha: 0.03)
let blueBg2 = CGColor(red: 0, green: 98.0/255.0, blue: 255.0/255.0, alpha: 0.08)

class BlurView: NSVisualEffectView {
  
  var borderGradient: CAGradientLayer!
  var bgGradient: CAGradientLayer!
  
  override var isFlipped: Bool {
    return true
  }
  
  
  override var frame: CGRect {
      didSet {
        let gradient = CAGradientLayer()
        gradient.frame =  CGRect(origin: CGPoint.zero, size: self.frame.size)
        gradient.colors = [blue2, blue, blue2]
        gradient.apply(angle: 90)

        let shape = CAShapeLayer()
        shape.lineWidth = 2
        
        shape.path = NSBezierPath(roundedRect: self.bounds, xRadius: 10, yRadius: 10).cgPath
        shape.strokeColor = NSColor.black.cgColor
        shape.fillColor = NSColor.clear.cgColor
        gradient.mask = shape
        
        self.layer?.replaceSublayer(borderGradient, with: gradient)
        borderGradient = gradient
        
        let gradient2 = CAGradientLayer()
        gradient2.frame =  CGRect(origin: CGPoint.zero, size: self.frame.size)
        gradient2.colors = [blueBg1, blueBg2]
        gradient2.apply(angle: 135)
        
        self.layer?.replaceSublayer(bgGradient, with: gradient2)
        bgGradient = gradient2
        
        
      }
  }
  
  
  override init(frame: CGRect) {
    super.init(frame: frame)

    self.material = .sidebar
    self.wantsLayer = true
    self.layer?.cornerRadius = 10.0
    self.layer?.masksToBounds = true
    
    let gradient = CAGradientLayer()
    gradient.frame =  CGRect(origin: CGPoint.zero, size: self.frame.size)
    gradient.colors = [blue, green, blue]
    gradient.apply(angle: 90)

    let shape = CAShapeLayer()
    shape.lineWidth = 2
    
    shape.path = NSBezierPath(roundedRect: self.bounds, xRadius: 10, yRadius: 10).cgPath
    shape.strokeColor = NSColor.black.cgColor
    shape.fillColor = NSColor.clear.cgColor
    gradient.mask = shape
    
    self.layer?.addSublayer(gradient)
    borderGradient = gradient
    
    let gradient2 = CAGradientLayer()
    gradient2.frame =  CGRect(origin: CGPoint.zero, size: self.frame.size)
    gradient2.colors = [blueBg1, blueBg2]
    gradient2.apply(angle: 135)
    
    self.layer?.addSublayer(gradient2)
    bgGradient = gradient2
  }
  
  

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

@objc (BlurViewManager)
class BlurViewManager: RCTViewManager {

  override static func requiresMainQueueSetup() -> Bool {
    return true
  }

  override func view() -> NSView! {
    return BlurView()
  }

}

相关问题