How to implement multiple PanGestures (Draggable views)?

后端 未结 3 870
后悔当初
后悔当初 2021-01-27 06:39

I want to have several objects that I can drag and drop.

Here\'s my code for moving one object (with lot of help from @vacawama):

import UIKit

class Vie         


        
相关标签:
3条回答
  • 2021-01-27 07:18

    The way a gesture recognizer works is that you attach it to a view. So if you have multiple views, and you want them to be draggable in the same way, attach a different pan gesture recognizer to each one.

    Now let's say you want them all to have the same action handler. No problem. In the action handler, you receive the current gesture recognizer as a parameter. It has a view property; that's the view it is attached to! So now you know that that's the view you're moving.

    0 讨论(0)
  • 2021-01-27 07:19

    If you are using Auto Layout, you shouldn't just move a view by altering its center. Anything that causes Auto Layout to run will move your view back to its original position.

    Here is an implementation of a new class called DraggableView that works with Auto Layout to provide views that can be dragged. It creates constraints in code for the width, height, X position, and Y position of the view. It uses its own UIPanGestureRecognizer to allow the view to be dragged.

    DraggableView.swift can be dropped into any project that needs draggable views. Take a look at ViewController.swift below to see how easy it is to use.

    DraggableView.swift

    import UIKit
    
    class DraggableView: UIView {
        let superView: UIView!
        let xPosConstraint:  NSLayoutConstraint!
        let yPosConstraint:  NSLayoutConstraint!
        var constraints: [NSLayoutConstraint] {
            get {
                return [xPosConstraint, yPosConstraint]
            }
        }
    
        init(width: CGFloat, height: CGFloat, x: CGFloat, y: CGFloat, color: UIColor, superView: UIView) {
            super.init()
    
            self.superView = superView
    
            self.backgroundColor = color
    
            self.setTranslatesAutoresizingMaskIntoConstraints(false)
    
            let panGestureRecognizer = UIPanGestureRecognizer()
            panGestureRecognizer.addTarget(self, action: "draggedView:")
            self.addGestureRecognizer(panGestureRecognizer)
    
            let widthConstraint = NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal,
                toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: width)
            self.addConstraint(widthConstraint)
    
            let heightConstraint = NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal,
                toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: height)
            self.addConstraint(heightConstraint)
    
            xPosConstraint = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal,
                toItem: superView, attribute: .Leading, multiplier: 1.0, constant: x)
    
            yPosConstraint = NSLayoutConstraint(item: self, attribute: .CenterY, relatedBy: .Equal,
                toItem: superView, attribute: .Top, multiplier: 1.0, constant: y)
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
    
        required init(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        func moveByDeltaX(deltaX: CGFloat, deltaY: CGFloat) {
            xPosConstraint.constant += deltaX
            yPosConstraint.constant += deltaY
        }
    
        func draggedView(sender:UIPanGestureRecognizer){
            if let dragView = sender.view as? DraggableView {
                superView.bringSubviewToFront(dragView)
                var translation = sender.translationInView(superView)
                sender.setTranslation(CGPointZero, inView: superView)
                dragView.moveByDeltaX(translation.x, deltaY: translation.y)
            }
        }
    }
    

    ViewController.swift

    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let dragView1 = DraggableView(width: 75, height: 75, x: 50, y: 50,
                color: UIColor.redColor(), superView: self.view)
            self.view.addSubview(dragView1)
            self.view.addConstraints(dragView1.constraints)
    
            let dragView2 = DraggableView(width: 100, height: 100, x: 150, y: 50,
                color: UIColor.blueColor(), superView: self.view)
            self.view.addSubview(dragView2)
            self.view.addConstraints(dragView2.constraints)
    
            let dragView3 = DraggableView(width: 125, height: 125, x: 100, y: 175,
                color: UIColor.greenColor(), superView: self.view)
            self.view.addSubview(dragView3)
            self.view.addConstraints(dragView3.constraints)
        }
    }
    

    UPDATE:

    Here is a version of DraggableView.swift that supports images as a subview.

    import UIKit
    
    class DraggableView: UIView {
        let superView: UIView!
        let xPosConstraint:  NSLayoutConstraint!
        let yPosConstraint:  NSLayoutConstraint!
        var constraints: [NSLayoutConstraint] {
            get {
                return [xPosConstraint, yPosConstraint]
            }
        }
    
        init(width: CGFloat, height: CGFloat, x: CGFloat, y: CGFloat, color: UIColor, superView: UIView, imageToUse: String? = nil, contentMode: UIViewContentMode = .ScaleAspectFill) {
            super.init()
    
            self.superView = superView
    
            self.backgroundColor = color
    
            self.setTranslatesAutoresizingMaskIntoConstraints(false)
    
            let panGestureRecognizer = UIPanGestureRecognizer()
            panGestureRecognizer.addTarget(self, action: "draggedView:")
            self.addGestureRecognizer(panGestureRecognizer)
    
            let widthConstraint = NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal,
                toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: width)
            self.addConstraint(widthConstraint)
    
            let heightConstraint = NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal,
                toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: height)
            self.addConstraint(heightConstraint)
    
            xPosConstraint = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal,
                toItem: superView, attribute: .Leading, multiplier: 1.0, constant: x)
    
            yPosConstraint = NSLayoutConstraint(item: self, attribute: .CenterY, relatedBy: .Equal,
                toItem: superView, attribute: .Top, multiplier: 1.0, constant: y)
    
            if imageToUse != nil {
                if let image = UIImage(named: imageToUse!) {
                    let imageView = UIImageView(image: image)
                    imageView.contentMode = contentMode
                    imageView.clipsToBounds = true
                    imageView.setTranslatesAutoresizingMaskIntoConstraints(false)
                    self.addSubview(imageView)
                    self.addConstraint(NSLayoutConstraint(item: imageView, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0))
                    self.addConstraint(NSLayoutConstraint(item: imageView, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0))
                    self.addConstraint(NSLayoutConstraint(item: imageView, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1.0, constant: 0))
                    self.addConstraint(NSLayoutConstraint(item: imageView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: 0))
                }
            }
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
    
        required init(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        func moveByDeltaX(deltaX: CGFloat, deltaY: CGFloat) {
            xPosConstraint.constant += deltaX
            yPosConstraint.constant += deltaY
        }
    
        func draggedView(sender:UIPanGestureRecognizer){
            if let dragView = sender.view as? DraggableView {
                superView.bringSubviewToFront(dragView)
                var translation = sender.translationInView(superView)
                sender.setTranslation(CGPointZero, inView: superView)
                dragView.moveByDeltaX(translation.x, deltaY: translation.y)
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-27 07:19

    Finally:

    Found this example which explained it in a easy way: http://www.raywenderlich.com/76020/using-uigesturerecognizer-with-swift-tutorial

    So, now multiple Pan's are working..

    Here's the code:

    import UIKit
    
    class ViewController: UIViewController {
    
    
    @IBOutlet weak var boxToMove1: UIView!
    @IBOutlet weak var boxToMove2: UIView!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    @IBAction func handlePan(objectToMove:UIPanGestureRecognizer) {
    
        let translation = objectToMove.translationInView(self.view)
        objectToMove.view!.center = CGPoint(x: objectToMove.view!.center.x + translation.x, y: objectToMove.view!.center.y + translation.y)
        objectToMove.setTranslation(CGPointZero, inView: self.view)
    
        println("\(objectToMove.view!.tag)") //Verify correct object received
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    }
    

    I linked up the "Pan Gesture Recognizer" from the "Object library" to each boxToMove. Then I linked the "Pan Gesture Recognizer" (both) to my @IBAction func handlePan...

    This is now working!!! Finally I understand the way this Gesture Recognizer is working!

    What I'm still trying to figure out is how to do all this linking programmatically.. Any idea?

    0 讨论(0)
提交回复
热议问题