Cocoa: 将 NSView 掩码设置为 CAShapeLayer

Cocoa: Set NSView mask as CAShapeLayer

您好,我正在尝试将 CAShapeLayer 设置为 NSView。但是我无法在 draw(_ dirtyRect: NSRect) 函数之外设置 CAShapeLayer 的角半径。

我必须使用 CAShapeLayer 来设置 NSBezierPath 来绘制自定义形状。所以,只有我使用 CAShapeLayer 而不是 NSView 的默认 CALayer.

代码如下:

扩展 NSBezierPath

extension NSBezierPath {
    
    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:
                fatalError("Unknown!")
            }
        }
        return path
    }
    
}

CustomView.swift

class CustomView: NSView{
    
    let shapeLayer = CAShapeLayer()
    
    var cornerRadius: CGFloat {
        
        set{
            
            
            let path = NSBezierPath(roundedRect: bounds, xRadius: newValue, yRadius: newValue)
            shapeLayer.path = path.cgPath
            path.close()
           
        }
        
        get{
            
            return shapeLayer.cornerRadius
        }
    }
    
    var backgroundColor: NSColor{
        
        set{
            
            shapeLayer.fillColor = newValue.cgColor
        }
        
        get{
            
            return NSColor(cgColor: shapeLayer.backgroundColor ?? .clear)!
         }
    }
    
    init() {
        
        super.init(frame: .zero)
        
        wantsLayer = true
        shapeLayer.masksToBounds = true
        layer?.addSublayer(shapeLayer)
//      layer?.mask = shapeLayer
//      layer?.masksToBounds = true
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ dirtyRect: NSRect) {
        
        shapeLayer.frame = dirtyRect
        
        let path = NSBezierPath(rect: dirtyRect)
        shapeLayer.path = path.cgPath
 
//      shapeLayer.cornerRadius = 22
        shapeLayer.borderColor = NSColor.black.cgColor
        shapeLayer.borderWidth = 2.0
        path.close()
    }
}

ViewController.swift

class ViewController: NSViewController {

    private lazy var customView: CustomView = {
        
        let customView = CustomView()
        
        view.addSubview(customView)
        customView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
        
            customView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            customView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            customView.heightAnchor.constraint(equalToConstant: 44),
            customView.widthAnchor.constraint(equalToConstant: 144)
        ])
        
        return customView
 
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
//        customView.layer?.cornerRadius  = 22
        customView.backgroundColor = .red
        customView.cornerRadius = 22

     }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }


}

当前输出:

预期输出:

Code is commented in the attached codes..

请帮我解决这个问题。提前谢谢你...

下面是一个简单的例子。首先,绘制一个简单的矩形,其子类为 NSView。所以实例化它以使用视图控制器创建一个对象。然后使用对象的图层使其成为具有描边颜色的圆形矩形。

// Subclass of `NSView` //
import Cocoa

class MyView: NSView {
    var fillColor: NSColor
    init(frame: CGRect, fillColor: NSColor){
        self.fillColor = fillColor
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect: NSRect) {
        super.draw(rect)
        
        let path = NSBezierPath()
        path.move(to: CGPoint.zero)
        path.line(to: CGPoint(x: 0.0, y: self.frame.height))
        path.line(to: CGPoint(x: self.frame.width, y: self.frame.height))
        path.line(to: CGPoint(x: self.frame.width, y: 0.0))
        path.line(to: CGPoint.zero)
        fillColor.set()
        path.fill()
    }
}

// View controller //
import Cocoa

class ViewController: NSViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let rect = CGRect(origin: CGPoint(x: 50, y: 50), size: CGSize(width: 200, height: 50))
        let myView = MyView(frame: rect, fillColor: NSColor.red)
        myView.wantsLayer = true
        if let myLayer = myView.layer {
            myLayer.cornerRadius = 24.0
            myLayer.borderWidth = 4.0
            //myLayer.borderColor = NSColor.green.cgColor
        }
        view.addSubview(myView)
    }
}