How to implement multiple PanGestures (Draggable views)?

后端 未结 3 881
后悔当初
后悔当初 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: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)
            }
        }
    }
    

提交回复
热议问题