Search code examples
iosswiftipadcalayer

iOS CALayer tap recognizer


I have a line like this: enter image description here

Which is drawn on a CAShapeLayer using the following code:

class LineView: UIView {

    let rwPath = UIBezierPath()
    let rwLayer = CAShapeLayer()
    let rwColor = UIColor(red: 11/255.0, green: 86/255.0, blue: 14/255.0, alpha: 1.0)

    func setData() {
        rwPath.move(to: CGPoint(x: 50.0, y: 50.0))
        for i in 1...200 {
            rwPath.addLine(to: CGPoint(x: i + 50, y: i + 50))
        }

        setUpRWLayer()
        layer.addSublayer(rwLayer)
    }

    private func setUpRWLayer() {
        rwLayer.path = rwPath.cgPath
        rwLayer.fillColor = nil
        rwLayer.lineCap = .butt
        rwLayer.lineDashPattern = nil
        rwLayer.lineDashPhase = 0.0
        rwLayer.lineJoin = .miter
        rwLayer.lineWidth = 3.0
        rwLayer.miterLimit = 10.0
        rwLayer.strokeColor = rwColor.cgColor
    }
}

I've been trying for a while to detect a tap on that line. I've tried using UITapGestureRecognizer and overriding touchesBegin:withEvent func, but nothing seems to work so I've come to ask here.

Hit test code:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let point = touches.first?.location(in: self)

    if let hitLayer = self.layer.hitTest(point!) as? CAShapeLayer {
        if (hitLayer.path?.contains(point!))! {
            print("Touched")
        }
    }
}

Solution

  • You need to create outline for it as it will work accurately for click event on CAShape layer

    Try this code and let me know if you face any issue

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
    
        guard let point = touch?.location(in: self.view) else { return }
        guard let sublayers = self.view.layer.sublayers else { return }
        var caShapelayers : [CAShapeLayer] = []
        for layer in sublayers {
            if layer is CAShapeLayer{
                caShapelayers.append(layer as! CAShapeLayer)
            }
        }
    
        for layer in caShapelayers {
            if let path = layer.path{
                let outline = path.copy(strokingWithWidth: 13, lineCap: .square, lineJoin: .round, miterLimit: 0)
    
                let iscontain = outline.contains(point)
                if iscontain  {
                    //    print(layer)
                    Singleton.sharedSingleton.showAlert(controller: self, message: "You want to delete this link?", title: "Are you sure?") { (buttonPressed) in
                        if (buttonPressed == "YES"){
                            layer.removeFromSuperlayer()
                        }
                    }
    
                }
            }
    
        }
    }