Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draggable UIView Swift 3

I want to be able to drag the objects on the screen, but they wont. I tried everything but still cant.

Here are the code.

func panGesture(gesture: UIPanGestureRecognizer) {
    switch gesture.state {
    case .began:
        print("Began.")
        for i in 0..<forms.count {
            if forms[i].frame.contains(gesture.location(in: view)) {
                gravity.removeItem(forms[i])
            }
        }
    case .changed:
        let translation = gesture.translation(in: forms[1])

        gesture.view!.center = CGPoint(x: gesture.view!.center.x + translation.x, y: gesture.view!.center.y + translation.y)

        gesture.setTranslation(CGPoint.zero, in: self.view)

        print("\(gesture.view!.center.x)=\(gesture.view!.center.y)")
        print("t;: \(translation)")
    case .ended:
        for i in 0..<forms.count {
            if forms[i].frame.contains(gesture.location(in: view)) {
                gravity.addItem(forms[i])
            }
        }
        print("Ended.")
    case .cancelled:
        print("Cancelled")
    default:
        print("Default")
    }
}

Also they have gravity. The forms are squares and circles.

Explanation: in .began - i disable the gravity for selected form. in .changed - i try to change the coordinates. in .end - i enable again gravity.

ScreenShot.

enter image description here

enter image description here

like image 237
Dpetrov Avatar asked May 01 '17 06:05

Dpetrov


People also ask

How to Create draggable View in Swift?

In order to make our view draggable, we have to add a gesture recognizer called UIPanGestureRecognizer . Apple's explanation of UIPanGestureRecognizer is quite straightforward: “A discrete gesture recognizer that interprets panning gestures.


3 Answers

Step 1 : Take one View which you want to drag in storyBoard.

@IBOutlet weak var viewDrag: UIView!

Step 2 : Add PanGesture.

var panGesture       = UIPanGestureRecognizer()

Step 3 : In ViewDidLoad adding the below code.

override func viewDidLoad() {
    super.viewDidLoad()

    panGesture = UIPanGestureRecognizer(target: self, action: #selector(ViewController.draggedView(_:)))
    viewDrag.isUserInteractionEnabled = true
    viewDrag.addGestureRecognizer(panGesture)

}

Step 4 : Code for draggedView.

func draggedView(_ sender:UIPanGestureRecognizer){
    self.view.bringSubview(toFront: viewDrag)
    let translation = sender.translation(in: self.view)
    viewDrag.center = CGPoint(x: viewDrag.center.x + translation.x, y: viewDrag.center.y + translation.y)
    sender.setTranslation(CGPoint.zero, in: self.view)
}

Step 5 : Output.

GIF

like image 89
Kirit Modi Avatar answered Oct 05 '22 18:10

Kirit Modi


Use below code for Swift 5.0

Step 1 : Take one UIView from Storyboard, drag it into your ViewController file and Create IBOutlet of UIView.

@IBOutlet weak var viewDrag: UIView!
var panGesture = UIPanGestureRecognizer()

Step 2 : In viewDidLoad() adding the below code.

override func viewDidLoad() {
super.viewDidLoad()
  let panGesture = UIPanGestureRecognizer(target: self, action:(Selector(("draggedView:"))))
  viewDrag.isUserInteractionEnabled = true
  viewDrag.addGestureRecognizer(panGesture)
}

Step 3 : Create func and add code to move the UIView as like below.

func draggedView(sender:UIPanGestureRecognizer){
    self.view.bringSubviewToFront(viewDrag)
    let translation = sender.translation(in: self.view)
    viewDrag.center = CGPoint(x: viewDrag.center.x + translation.x, y: viewDrag.center.y + translation.y)
    sender.setTranslation(CGPoint.zero, in: self.view)
}

Hope this will help someone.

like image 39
Dilip Tiwari Avatar answered Oct 05 '22 16:10

Dilip Tiwari


It's very easy if you subclass a view:

DraggableView...

class DraggableView: UIIView {
    
    var fromleft: NSLayoutConstraint!
    var fromtop: NSLayoutConstraint!
    
    override func didMoveToWindow() {
        super.didMoveToWindow()
        if window != nil {
            fromleft = constraint(id: "fromleft")!
            fromtop = constraint(id: "fromtop")!
        }
    }
    
    override func common() {
        super.common()
        let p = UIPanGestureRecognizer(
           target: self, action: #selector(drag))
        addGestureRecognizer(p)
    }
    
    @objc func drag(_ s:UIPanGestureRecognizer) {
        let t = s.translation(in: self.superview)
        fromleft.constant = fromleft.constant + t.x
        fromtop.constant = fromtop.constant + t.y
        s.setTranslation(CGPoint.zero, in: self.superview)
    }
}
  1. Drop a UIView in your scene.

  2. As normal, add a constraint from the left (that's the x position) and add a constraint from the top (that's the y position).

  3. In storyboard simply simply name the constraints "fromleft" and "fromtop"

enter image description here

You're done.

It now works perfectly - that's it.

What is that handy constraint( call ?

Notice the view simply finds its own constraints by name.

In Xcode there is STILL no way to use constraints like IBOutlets. Fortunately it is very easy to find them by "identifier". (Indeed, this is the very purpose of the .identifier feature on constraints.)

extension UIView {
    
    func constraint(id: String) -> NSLayoutConstraint? {
        let cc = self.allConstraints()
        for c in cc { if c.identifier == id { return c } }
        //print("someone forgot to label constraint \(id)") //heh!
        return nil
    }
    
    func allConstraints() -> [NSLayoutConstraint] {
        var views = [self]
        var view = self
        while let superview = view.superview {
            views.append(superview)
            view = superview
        }
        return views.flatMap({ $0.constraints }).filter { c in
            return c.firstItem as? UIView == self ||
                c.secondItem as? UIView == self
        }
    }

Tip...edge versus center!

Don't forget when you make the constraints on a view (as in the image above):

you can set the left one to be either:

  • to the left edge of the white box, or,
  • to the center of the white box.

Choose the correct one for your situation. It will make it much easier to do calculations, set sliders, etc.


Footnote - an "initializing" UIView, UI "I" View,

// UI "I" View ... "I" for initializing
// Simply saves you typing inits everywhere
import UIKit
class UIIView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        common()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        common()
    }
    func common() { }
}
like image 36
Fattie Avatar answered Oct 05 '22 16:10

Fattie