Search code examples
swiftuiviewdrawuibezierpathcgpoint

how to place image on top of uiview drawing (swift5)


My code below places a behind a drawing area. So as you can see in the image below. Anything I draw goes in front of the lines. I want to make so whatever i draw goes behind the lines. All of my code is attached below. The image is in the assets folder as well.

class ViewController: UIViewController {
    var editBtn = UIButton()
    var canVasView = UIView()
    var path = UIBezierPath()
    var startPoint = CGPoint()
    var touchPoint = CGPoint()

    func addArrowImageToButton(button: UIButton, arrowImage:UIImage = #imageLiteral(resourceName: "graph.png") ) {
        let btnSize:CGFloat = 32
        let imageView = UIImageView(image: arrowImage)
        let btnFrame = button.frame

        button.bringSubviewToFront(imageView)
    }

    override func viewDidAppear(_ animated: Bool) {
        self.addArrowImageToButton(button: editBtn)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        setup()
        draw()
        view.addSubview(editBtn)
        view.addSubview(canVasView)

        editBtn.backgroundColor = UIColor.orange
        canVasView.backgroundColor = UIColor.purple

        editBtn.translatesAutoresizingMaskIntoConstraints = false
        canVasView.translatesAutoresizingMaskIntoConstraints = false

        let myLayer = CALayer()
        let myImage = UIImage(named: "graph.png")?.cgImage
        myLayer.frame = CGRect(x: 40, y: -80, width: 300, height: 300)
        myLayer.contents = myImage
        canVasView.layer.addSublayer(myLayer)

        self.view.addSubview(canVasView)

        NSLayoutConstraint.activate ([
            canVasView.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :175),
            canVasView.topAnchor.constraint(equalTo: view.centerYAnchor, constant : 100),
            canVasView.widthAnchor.constraint(equalToConstant: 350),
            canVasView.heightAnchor.constraint(equalToConstant: 180),

            editBtn.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :175),
            editBtn.topAnchor.constraint(equalTo: view.centerYAnchor, constant : 0),
            editBtn.widthAnchor.constraint(equalToConstant: 350),
            editBtn.heightAnchor.constraint(equalToConstant: 180),
        ])

        editBtn.addTarget(self, action: #selector(didTapEditButton), for: .touchUpInside)
    }

    @objc func didTapEditButton() {
        path.removeAllPoints()
        canVasView.layer.sublayers = nil
        canVasView.setNeedsDisplay()

        self.addArrowImageToButton(button: editBtn)
    }

    func setup(){
        editBtn.layer.cornerRadius = 20
        canVasView.clipsToBounds = true
        canVasView.isMultipleTouchEnabled = false
    }

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

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        if let point = touch?.location(in: canVasView){
            touchPoint = point
        }

        path.move(to: startPoint)
        path.addLine(to: touchPoint)
        startPoint = touchPoint
        draw()
    }

    func draw() {
        let strokeLayer = CAShapeLayer()
        strokeLayer.fillColor = nil
        strokeLayer.lineWidth = 5
        strokeLayer.strokeColor = UIColor.blue.cgColor
        strokeLayer.path = path.cgPath
        canVasView.layer.addSublayer(strokeLayer)
        canVasView.setNeedsDisplay()
    }
}

enter image description here


Solution

  • To draw behind the lines image you need to add your stroke layer behind it. To do so, declare myLayer outside of viewDidLoad then change your draw function to:

    func draw() {
        let strokeLayer = CAShapeLayer()
        strokeLayer.fillColor = nil
        strokeLayer.lineWidth = 5
        strokeLayer.strokeColor = UIColor.blue.cgColor
        strokeLayer.path = path.cgPath
        canVasView.layer.insertSublayer(strokeLayer, below: myLayer) //draw behind myLayer
        canVasView.setNeedsDisplay()
    }