围绕 CAShape 层绘制矩形

Draw rectangle around CAShape Layer

我是 Swift 的新手,也是 Core Animation 的新手。我想像这样在 CAShapeLayer 周围创建矩形框 image,但我不知道。

具体来说,我正在通过 PocketSVG 解析 SVG 图像并将其 UIBezierPath 转换为 CAShapeLayer然后我将这些图层添加到 UI Image View 作为 sublayer.

这是我将 Path 转换为 CaShape Layer.

的代码
fileprivate func createLayer(path: SVGBezierPath) -> CAShapeLayer {
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    if let any = path.svgAttributes["stroke"] {
        shapeLayer.strokeColor = (any as! CGColor)
    }
    
    if let any = path.svgAttributes["fill"] {
        shapeLayer.fillColor = (any as! CGColor)
    }
    return shapeLayer
}

下面是代码,我在其中添加图层到 UIImage View (backgroundIV)

        for path in paths {
        path.apply(.init(scaleX: scale, y: scale))
        let layer = createLayer(path: path)
        layer.frame = self.backgroundIV.bounds
        self.backgroundIV.layer.addSublayer(layer)
    }

我还添加了 TapGesture, RotateGesture, ScaleGesture 和 PanGesture 到 CA Shape Layers,下面是代码。

    @objc func rotateLayer(_ sender: UIRotationGestureRecognizer) {
    selectedLayer?.setAffineTransform(CGAffineTransform(rotationAngle: sender.rotation))
}

@objc func selectLayer(_ sender: UITapGestureRecognizer) {
    let point = sender.location(in: self.backgroundIV)
    guard let layers = self.backgroundIV.layer.sublayers
    else { return }
    var hitLayers: [CAShapeLayer] = []
    
    selectedLayer?.lineWidth = CGFloat(0)
    
    for subLayer in layers {
        if let thisLayer = subLayer as? CAShapeLayer,
           let pth = thisLayer.path {
            let layerPoint: CGPoint = thisLayer.convert(point, from: self.backgroundIV.layer)
            if pth.contains(layerPoint) {
                hitLayers.append(thisLayer)
            }
        }
    }
    
    selectedLayer = hitLayers.last
    selectedLayer?.strokeColor = UIColor.red.cgColor
    selectedLayer?.lineWidth = CGFloat(3)
    selectedLayerRect = CGRect(origin: point, size: CGSize(width: 100, height: 100))
    showPopupMenu()
    
}

@objc func moveLayer(_ recognizer: UIPanGestureRecognizer) {
    let p = recognizer.location(in: self.backgroundIV)
    selectedLayer?.position = p
}

@objc func scaleLayer(_ sender: UIPinchGestureRecognizer) {
    selectedLayer?.transform = CATransform3DMakeScale(sender.scale, sender.scale, 1)
}

SelectLayer 方法的最后几行中,我通过增加描边宽度和颜色来突出显示 selected 层。

selectedLayer?.strokeColor = UIColor.red.cgColor
selectedLayer?.lineWidth = CGFloat(3)

当我取消 select 图层时,我只是将其 lineWidth 值设置为 0,这不是一个好的做法。

有什么方法可以像这样创建矩形框 image?

如果您想在图层的框架周围画一个框,那很容易。只需设置 aLayer.borderWidth=1aLayer.borderColor=UIColor.someColor.cgColor.

系统会在图层周围添加边框。

但是,如果您图层的框架比它们包含的路径大,您的矩形可能会比您想要的大。

试试这个..
希望对您有所帮助...

import UIKit
class ViewController : UIViewController {

let containerView: UIView = {
    let view = UIView()
    view.backgroundColor = .clear
    return view
}()

override func viewDidLoad() {
    super.viewDidLoad()
    
    containerView.frame = CGRect(x: view.frame.width/2 - 100, y: view.frame.height/2 - 100, width: 200, height: 200)
    view.addSubview(containerView)
    
    drawRectangle()
}

private func drawRectangle() {
    
    let path = UIBezierPath()
    path.move(to: CGPoint(x: 0, y: 0))
    path.addLine(to: CGPoint(x: 200, y: 0))
    path.addLine(to: CGPoint(x: 200, y: 200))
    path.addLine(to: CGPoint(x: 0, y: 200))
    path.addLine(to: CGPoint(x: 0, y: 0))
    
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    shapeLayer.strokeColor = UIColor.red.cgColor
    shapeLayer.fillColor = UIColor.black.cgColor
    shapeLayer.lineWidth = 3
    
    containerView.layer.addSublayer(shapeLayer)
    }
}

如果我没理解错的话,你的问题是“如何绘制虚线轮廓”?

如果是这样,您可以在形状图层上设置 .lineDashPattern

例如:

    selectedLayer?.strokeColor = UIColor.red.cgColor
    selectedLayer?.lineWidth = 3.0
    
    // set the dash pattern for the stroke
    selectedLayer?.lineDashPattern = [10, 10]

这是我问题的答案

    var selectedLayer: CAShapeLayer! {
    didSet {
        guard let layer = selectedLayer else {return}
        box.frame = layer.path?.boundingBox ?? CGRect()
        box.borderWidth = layer.contentsScale * 3
        box.borderColor = UIColor.red.cgColor
        self.updateControlView()
        layer.addSublayer(box)
    }
    willSet {
        self.controlView.isHidden = true
        box.removeFromSuperlayer()
    }
}

Output