Kodeco Forums

UIGestureRecognizer Tutorial: Getting Started

Learn how to use UIGestureRecognizer with Swift in your iOS apps, as well as how make your own custom gestures.


This is a companion discussion topic for the original entry at http://www.raywenderlich.com/76020/using-uigesturerecognizer-with-swift-tutorial

Hey Caroline, I would like to know why the vector’s magnitude has to be divided by 200 (constant value, can it be other value???) in the deceleration tutorial?

Is there an update to swift 2.1+ and iOS 9+ for the gestureRecognizer tutorial?

No, but perhaps I can help you through any difficulty?

The archived forum might have some answers too, as there was quite a bit of discussion on this topic.

oh… yes how do I see that? I hadn’t started the tut yet but one thing i’ve been running into with other ones is… scaling views results in pixilation… also i was looking for an economical way to mimic the way that blek takes a pan gesture and draws such a nice line, generating sound based on the user’s velocity… I’m trying to understand how to draw multiple lines from multiple simultaneous pans with let’s say 2-3 fingers… I’m just trying to get a better understanding of gesture recognizers in general…

The archive’s here: http://archive.raywenderlich.com/forums/viewtopic.php?f=20&t=17966

If you want to see the archive for any other topic, if you go to the topic itself, down at the bottom of the page, where it has the discussion on the topic, just above that is a link to the archive for that topic. (I hope that works for all topics!)

Scaling will result in pixellation.

The way I have dealt with that in the past is track the scale while pinching, then replace the scale with 1.0 (normal scale) and resize the frame and redraw the view if necessary.

I remember blek - was a great game. I think that’s probably done with touches rather than gestures in touchesBegan etc, but I could be wrong.

right now I’m trying to wrap my head around what must be a simple problem, but it’s eluding me… how to use a pan gesture to drag an object, but keep it let’s say 20 pixels to the left and 20 pixels above the finger’s location, so that you can continue to see the object without the finger blocking it? also, is there a way to add spring animation to the picking up (starting to pan) and putting down (letting go) of the object, based on the velocity that the pan happened? I am so lost as I learn iOS sometimes lol. i think the best example would be in games like 1010 or 100! where there appears a small object, and as soon as you touch it, it animates to a larger version of itself offset by 20-30 pixels from your finger, allowing you to see where you put it. I’d like to do that…

Have you been through the tutorial yet? You can get the touch location with locationInView(_:slight_smile: and then set the centre of the view depending on the touch location. (The tutorial doesn’t specifically cover that, but if you get a feel for how gestures work and then check out the Apple documentation of all the methods available to UIPanGestureRecognizer and its super class UIGestureRecognizer, then it might become more obvious.)

You could add an animation to the view at the start and end of the gesture. Marin Todorov has written lots about animations on this site, including a whole book.

oo thanks for showing me that… ah I haven’t but I did manage to come up with this code in the meantime… now I just want to animate the sudden hop the view makes when dragging first begins… something like a spring motion instead of an abrupt change…

        func didPan(panGR: UIPanGestureRecognizer) {
        self.superview!.bringSubviewToFront(self)
        let location = panGR.locationInView(superview!)
        switch (panGR.state) {
        case UIGestureRecognizerState.Changed:
            self.center.x = location.x
            self.center.y = location.y - bounds.height * 0.8
            break
        case UIGestureRecognizerState.Began:
            //need code here to animate the sudden move when first dragging.
            break
        default:
            break
        }

What I really need a tutorial on, apparently, is locating all the properties of a class through the crazy documentation… for example, when I went to the apple docs, I found .translation but not .location… i had to find that on stackOverflow… I wonder what other properties there are which aren’t well documented heh.

For animating, this one might get you started: https://www.raywenderlich.com/113674/ios-animation-tutorial-getting-started

I haven’t been through it to make sure it’s all Swift 2.1, but it’s a very new one so should be OK.

When you look at the Apple docs, don’t forget to look at the super class. location is in the super class of UIPanGestureRecognizer, so won’t show in UIPanGestureRecognizer’s documentation, but there’s a link you can click at the top of the documentation page to go up the class hierarchy.

1 Like

Couple of comments on code style - looks good so far :slight_smile: - we (meaning the RW team) don’t use self unless it’s inside a closure, although that’s a matter for personal preference. You can just use .Changed and .Began rather than UIGestureRecognizerState.Changed, because Swift can infer the type from the state property.
And you don’t need break in any of the case statements.
If you want default not to do anything, just do default: ()

it’s those tiny little things that make all the difference! forever burnt in: make sure to look at the superclass’s docs too :slightly_smiling:

1 Like

ok let me fix those things… i’m learning here… so many paradigms to know… agile coding… clean code… systematic coding… mvc… i definitely like all these… now i got it getting bigger and being bouncy but i’d prefer it does so on a tap and hold, not the beginning of the gesture… not sure where to deal with that… touches began and pan… what’s the proper way to handle that?

and thanks for holding my hand a little on this one! it’s so cold and dark out here in iOS learning land, usually, lol.

//Mark: Methods

func didPan(panGR: UIPanGestureRecognizer) {
    superview!.bringSubviewToFront(self)
    let location = panGR.locationInView(superview!)
    switch (panGR.state) {
    case .Changed:
        center.x = location.x
        center.y = location.y - bounds.height * 0.8
    case .Began:
        UIView.animateWithDuration(1 , delay: 0, usingSpringWithDamping: 0.36, initialSpringVelocity: 10, options: [], animations: { [unowned self] in
            self.center.x = location.x
            self.center.y = location.y - self.bounds.height * 0.8
            self.transform = CGAffineTransformScale(self.transform, 1.5, 1.5)
            }, completion: nil)
    case .Ended:
        UIView.animateWithDuration(0.5 , delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 20, options: [], animations: { [unowned self] in
            self.transform = CGAffineTransformScale(self.transform, 1/1.5, 1/1.5)
            }, completion: nil)
    default:()
    }

You could try using a UILongPressGestureRecognizer. That should work with a Pan.

i really want the object to “wake up” that is do the spring action, enlarging, coming to front… right as soon as a tap happens… if it’s just a brief tap, it springs larger then smaller right away, but is left on top… so would long tap really be the right thing for that? not sure how to code it in general… does the code to accomplish this go in the touchesBegan method? then does that mean the code I have in the pan gesture code is duplicated? just trying to understand the best practices way to accomplish the minor change…

I haven’t done that yet myself, but perhaps a combination of this tutorial: https://www.raywenderlich.com/104744/uigesturerecognizer-tutorial-creating-custom-recognizers
and this piece of documentation: Apple Developer Documentation
might get you understanding how UIGestureRecognizers work.

Hi Caroline,

I’m having some issues where after I have rotated my image the direction in which I pan it is then reversed. E.g if I rotate it 180 degrees, when I try to then move the image up it moves down etc.

Can you offer any help?

Thanks,
Patrick

Hi Patrick

The sample does not do that - have you checked your code against the finished sample?

Hi Caroline,
first thank you for the great tutorial! I want to animate the monkey to move back to it’s original position after the gesture has ended. I used AutoLayout and tied:

case .Ended:
self.monkey.setNeedsUpdateConstraints()

that makes him hop back. Then I tried:

var originalMonkeyPosition: CGPoint?

 override func viewDidLoad() {
        super.viewDidLoad()
       // record original position
       originalMonkeyPosition = monkey.center
}
func handlePan(recognizer: UIPanGestureRecognizer){
        switch panGesture.state{
            
        case .Began:
            
        case .Changed:
            // follow the pan
            let translation = recognizer.translationInView(self.view)
            monkey.center = CGPointMake(monkey.center.x + dCenter.x, monkey.center.y + dCenter.y)
            recognizer.setTranslation(CGPointZero, inView: self.view)
          
            
        case .Ended:
           UIView.animateWithDuration(1, delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
                    
                    
                    self.monkey.center = originalMonkeyPosition
                    self.view.layoutIfNeeded()
                    
                    
                    }, completion: nil)
          self.monkey.setNeedsUpdateConstraints()
            
        default: break
            
        }// end switch
}

Now he animates back but makes a weird hopp at the beginnig…
I found a lot of help for draging views around but none for animating them back.

Any help would be appeciated.