I am developing an application which the user will be able to drag and drop items on a canvas and when he releases the image it is drawn on the canvas.
This is my DragImage class which handle the touches:
class DragImages: UIImageView {
    var originalPos : CGPoint!
    var dropTarget: UIView?
    override init (frame : CGRect){
        super.init(frame: frame)
    }
    required init?(coder aDecoder : NSCoder){
        super.init(coder : aDecoder)
    }
    override func touchesBegan(_ touches : Set<UITouch>,with event: UIEvent?){
        originalPos = self.center
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first{
            let position = touch.location(in: self.superview)
            self.center = CGPoint(x : position.x, y : position.y)
        }
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first, let target = dropTarget{
            let position = touch.location(in: self.superview)
            if target.frame.contains(position){
               NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "onTargetDropped"), object: nil))
            }else {
                self.center = originalPos
            }
        }
        print(self.center.x, self.center.y)
        self.center = originalPos
    }
    func getEndPosX() -> CGFloat{
        return self.center.x
    }
    func getEndPosY() -> CGFloat {
        return self.center.y
    }
}
In my ViewController class I added this piece of code to handle the touches etc:
  ornament1.dropTarget = xmasTree
    ornament2.dropTarget = xmasTree
    ornament3.dropTarget = xmasTree
    ornament4.dropTarget = xmasTree
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.itemDroppedOnTree(_:)), name: NSNotification.Name(rawValue: "onTargetDropped"), object: nil)
}
func itemDroppedOnTree(_ notif : AnyObject){
}
I managed to get the X and Y position when the image is dragged on the canvas but i cant find a way to recognise which of the 4 images is being dropped in order for me to draw that specific one!
You could add the sender to your notification (and also the position):
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "onTargetDropped"), object: self, userInfo: ["position":position]))
and get it later in itemDroppedOnTree:
func itemDroppedOnTree(_ notif : NSNotification){
    let position = notif.userInfo["position"]
    let sender = notif.object as! DragImage
    if sender === dragImage1 {
         //... 
    } else if sender === dragImage2 {
         //...
    }
 }
I recommend against it though and plead to use a delegate to inform the ViewController instead. (Opinion based: In general, use Notifications for to-many broadcasts only.)
The delegate function should have the sender as first parameter. According to func tableView: tableView:UITableView, cellForRowAt indexPath:IndexPath).
This way you know which image is sending its new position and can compare it to your property like in the above example:
 if dragImage === dragImage1 {...
Your code plus working delegate to paste to Playground:
import UIKit
import PlaygroundSupport
protocol DragImageDelegate: class {
    func dragimage(_ dragImage:DragImage, didDropAt position:CGPoint)
}
class DragImage: UIImageView {
    weak var delegate: DragImageDelegate?
    var originalPos : CGPoint!
    var dropTarget: UIView?
    override init (frame : CGRect) {
       super.init(frame: frame)
        isUserInteractionEnabled = true
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func touchesBegan(_ touches : Set<UITouch>,with event: UIEvent?){
        originalPos = self.center
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first{
            let position = touch.location(in: self.superview)
            self.center = CGPoint(x : position.x, y : position.y)
        }
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first, let target = dropTarget {
            let position = touch.location(in: self.superview)
            if target.frame.contains(position){
                print(self.center.x, self.center.y)
                guard let delegate = self.delegate else {
                    print("delegate not set")
                    return
                }
                print(self.center.x, self.center.y)
                delegate.dragimage(self, didDropAt: position)
                return
            }
        }
        self.center = originalPos
    }
}
class MyVC: UIViewController, DragImageDelegate {
    let dragImage1 = DragImage(frame: CGRect(x: 0.0, y: 0.0, width: 30.0, height: 30.0))
    let dragImage2 = DragImage(frame: CGRect(x: 0.0, y: 100.0, width: 30.0, height: 30.0))
    override func viewDidLoad() {
        let target = UIView(frame: CGRect(x: 200.0, y: 400.0, width: 30.0, height: 30.0))
        target.backgroundColor = .black
        view.addSubview(target)
        dragImage1.backgroundColor = .white
        dragImage2.backgroundColor = .white
        dragImage1.dropTarget = target
        dragImage2.dropTarget = target
        view.addSubview(dragImage1)
        view.addSubview(dragImage2)
        dragImage1.delegate = self
        dragImage2.delegate  = self
    }
    private func move(_ view:UIView, to position:CGPoint) {
        view.frame = CGRect(x: position.x, y: position.y, width: view.frame.size.width, height: view.frame.size.height)
    }
    // MARK: - DragImageDelegate
    func dragimage(_ dragImage: DragImage, didDropAt position: CGPoint) {
        if dragImage === dragImage1 {
            move(dragImage1, to: position)
        } else if dragImage === dragImage2 {
            move(dragImage2, to: position)
        }
    }
}
var container = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 300.0, height: 600.0))
let myVc = MyVC()
myVc.view.frame = CGRect(x: 0.0, y: 0.0, width: 300.0, height: 600.0)
myVc.view.backgroundColor = .green
container.addSubview(myVc.view)
PlaygroundPage.current.liveView = container
Result:

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With