如何实现多个PanGestures(可拖动视图)?

时间:2014-11-25 01:02:17

标签: swift autolayout xcode6 nslayoutconstraint uipangesturerecognizer

我希望有几个可以拖放的对象。

这是我移动一个对象的代码(来自@vacawama的大量帮助):

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var panView: UIView!

@IBOutlet weak var panViewCenterX: NSLayoutConstraint!
@IBOutlet weak var panViewCenterY: NSLayoutConstraint!

let panRec = UIPanGestureRecognizer()

override func viewDidLoad() {
    super.viewDidLoad()

    panRec.addTarget(self, action: "draggedView:")
    panView.addGestureRecognizer(panRec)

// Do any additional setup after loading the view, typically from a nib.
}

func draggedView(sender:UIPanGestureRecognizer){

    self.view.bringSubviewToFront(sender.view!)
    var translation = sender.translationInView(self.view)

    panViewCenterY.constant += translation.y
    panViewCenterX.constant += translation.x

    sender.setTranslation(CGPointZero, inView: self.view)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}   

}

我想在我的项目中有更多对象:

 @IBOutlet weak var panView2: UIView!
 @IBOutlet weak var panView3: UIView!
 @IBOutlet weak var panView4: UIView!
 ...

那么,实现这一目标的最简单方法是什么,我可以有多个panView,我可以独立移动(当时一个)?

3 个答案:

答案 0 :(得分:3)

如果您使用自动布局,则不应仅通过更改其中心来移动视图。任何导致自动布局运行的内容都会将您的视图移回原位。

以下是名为DraggableView的新类的实现,该类与自动布局一起使用以提供可以拖动的视图。它在代码中为视图的宽度,高度,X位置和Y位置创建约束。它使用自己的UIPanGestureRecognizer来允许拖动视图。

DraggableView.swift 可以放入需要可拖动视图的任何项目中。看看下面的 ViewController.swift ,看看它是多么容易使用。

<强> 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)
    }
}

<强>更新

以下是支持图像作为子视图的 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, 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)
        }
    }
}

答案 1 :(得分:0)

手势识别器的工作方式是将其附加到视图中。因此,如果您有多个视图,并且希望它们以相同的方式可拖动,请为每个视图附加不同的平移手势识别器。

现在让我们说你希望他们拥有相同的动作处理程序。没问题。在动作处理程序中,您将当前手势识别器作为参数接收。它有view属性;这是它附加的视图!所以现在你知道那是你正在移动的观点。

答案 2 :(得分:0)

最后:

找到这个简单解释的例子: http://www.raywenderlich.com/76020/using-uigesturerecognizer-with-swift-tutorial

所以,现在有多个Pan正在工作..

以下是代码:

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.
}
}

我联系了#34; Pan Gesture Recognizer&#34;来自&#34;对象库&#34;每个boxToMove。然后我联系了#34; Pan Gesture Recognizer&#34; (两者)到我的@IBAction func handlePan ......

现在正在工作!!! 最后,我理解了这个Gesture Recognizer的工作方式!

我还想弄清楚如何以编程方式完成所有这些链接..有什么想法吗?