Search code examples
iosswiftcore-graphics

How can I select a specific circle?


I have created Circle using "draw" and can place it anywhere on view. but when I want to move a specific circle by clicking it. it selects "LAST" created circle. how can I select a specific circle? please guide me for the same. if anything else you need let me know.

**CircleView**
import UIKit

class CircleView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .clear
    }


    required init(coder aDecoder : NSCoder) {
        fatalError("init(coder : ) has not been implemented")
    }

    override func draw(_ rect: CGRect) {
        if let context = UIGraphicsGetCurrentContext(){

            context.setLineWidth(2)
            UIColor.yellow.set()


            let circleCenter = CGPoint(x: frame.size.width / 2, y: frame.self.height / 2)
            let circleRadius = (frame.size.width - 10) / 2

            context.addArc(center: circleCenter, radius: circleRadius, startAngle: 0, endAngle: .pi * 2, clockwise: true)

            context.strokePath()
        }
    }


}

**ViewController**
import UIKit

class ViewController: UIViewController {


    var circleView = CircleView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
    let circleWidth = CGFloat(100)
    var lastCircleCenter = CGPoint()
    var currentCenter = CGPoint()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.lightGray
        circleView.isUserInteractionEnabled = true
    }


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

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

        if let touch = touches.first{
            let circleCenter = touch.location(in: view)

            if circleCenter == lastCircleCenter{

            let circleHeight = circleWidth

            circleView = CircleView(frame: CGRect(x: circleCenter.x - circleWidth / 2, y: circleCenter.y - circleWidth / 2, width: 100, height: 100))

                view.addSubview(circleView)
            }
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

        guard let touch = touches.first else {
            return
        }
        let location = touch.location(in: view)
        circleView.center = location
    }

}

how can I select a specific circle? please guide me for the same. if anything else you need let me know. how can I select a specific circle? please guide me for the same. if anything else you need let me know.


Solution

  • If you are creating multiple circles and adding them to your view, I would suggest to keep track of the created circles in a collection. That way on each touch you can check if the coordinate matches any of the created circles. Based on that you can determine if to create a new circle or to move an existing one.

    Example:

    class ViewController: UIViewController {
        var circleViews: [CircleView] = []
        let circleWidth = CGFloat(100)
        var draggedCircle: CircleView?
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            // Do nothing if a circle is being dragged
            // or if we do not have a coordinate
            guard draggedCircle == nil, let point = touches.first?.location(in: view) else {
                return
            }
    
            // Do not create new circle if touch is in an existing circle
            // Keep the reference of the (potentially) dragged circle
            if let draggedCircle = circleViews.filter({ UIBezierPath(ovalIn: $0.frame).contains(point) }).first {
                self.draggedCircle = draggedCircle
                return
            }
    
            // Create new circle and store in an array
            let offset = circleWidth / 2
            let rect = CGRect(x: point.x - offset, y: point.y - offset, width: circleWidth, height: circleWidth)
            let circleView = CircleView(frame: rect)
            circleViews.append(circleView)
            view.addSubview(circleView)
            // The newly created view can be immediately dragged
            draggedCircle = circleView
        }
    
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            // If touches end then a circle is never dragged
            draggedCircle = nil
        }
    
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            guard let draggedCircle = draggedCircle, let point = touches.first?.location(in: view) else {
                return
            }
    
            draggedCircle.center = point
        }
    }