This post is part of my collection: Swift 2 – For Beginners.
This example shows how gesture recognizers works.
Adding gestures programmatically
It is possible to add gesture recognizers programmatically to a view using the method addGestureRecognizer. To do that we can use these lines of code:
static func addSwipeGestureRecognizer(targetView: UIView, swipeDirection: UISwipeGestureRecognizerDirection, actionTarget: AnyObject?, action: Selector){ // Create gesture recognizer let swipeRecognizer = UISwipeGestureRecognizer(target: actionTarget, action: action) // Set swipe direction swipeRecognizer.direction = swipeDirection // Add recognizer to target view targetView.addGestureRecognizer(swipeRecognizer) }
Swipe
However you can also add gestures using “drag and drop” in your storyboard from the object library:
It is also possible to configure some parameters using XCode, i.e the swipe direction.
Once you have your gesture in the storyboard you can select it and drag it to your ViewController to create the action that should be executed when the gesture was recognized.
@IBAction func onViewSwipe(recognizer: UISwipeGestureRecognizer) { print("swipe down") }
Rotate
We can use the rotation gesture recognizer to rotate a view:
@IBOutlet weak var ghostImage: UIImageView! // Rotate @IBAction func onGhostRotate(recognizer: UIRotationGestureRecognizer) { print("onGhostRotate \(recognizer.rotation)") // Apply gesture rotation to ghost view ghostImage.transform = CGAffineTransformRotate(ghostImage.transform, recognizer.rotation) // Reset recognizer rotation recognizer.rotation = 0 }
Tap
Using a tap gesture recognizer and what we learnt before when can play a sound when the user tap our image:
@IBAction func onGhostTapped(sender: UITapGestureRecognizer) { let audioPath = NSBundle.mainBundle().pathForResource("punch", ofType: "mp3")! do { // Initialize the player player = try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath)) // Play player.play() } catch{ print("Error creating audio player.") } }
Panning
The pan gesture recognizer allows us to drag and drop views in our application:
@IBAction func onGhostPanning(recognizer: UIPanGestureRecognizer) { GestureHelper.applyGestureTranslationToGestureView(recognizer, parentView: self.view) }
static func applyGestureTranslationToGestureView(recognizer: UIPanGestureRecognizer, parentView: UIView){ // Apply translation recognizer view if let recognizerView = recognizer.view { // Get recognized translation let translation = recognizer.translationInView(parentView) // Calculate new center let originalCenter = recognizerView.center recognizerView.center = CGPoint(x:originalCenter.x + translation.x, y:originalCenter.y + translation.y) } // Reset recognizer translation recognizer.setTranslation(CGPointZero, inView: parentView) }
Shake
There is not shake gesture recognizer, to do something when the user shake the phone we have to override the method motionEnded. This code resets the position and rotation of our ghost when the user shakes the phone:
override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) { if event?.subtype == UIEventSubtype.MotionShake{ // Reset initial position ghostImage.center = ghostInitialPosition // Reset rotation and scale ghostImage.transform = CGAffineTransform() } }
Complete example:
GestureHelper
import UIKit public class GestureHelper { // this adds a helper in "code behind" normally you would do it adding the gesture using the storyboard and then the gesture action to the controller... static func addSwipeGestureRecognizer(targetView: UIView, swipeDirection: UISwipeGestureRecognizerDirection, actionTarget: AnyObject?, action: Selector){ // Create gesture recognizer let swipeRecognizer = UISwipeGestureRecognizer(target: actionTarget, action: action) // Set swipe direction swipeRecognizer.direction = swipeDirection // Add recognizer to target view targetView.addGestureRecognizer(swipeRecognizer) } static func applyGestureTranslationToGestureView(recognizer: UIPanGestureRecognizer, parentView: UIView, inertia: Bool = true){ // Apply translation recognizer view if let recognizerView = recognizer.view { // Get recognized translation let translation = recognizer.translationInView(parentView) // Calculate new center let originalCenter = recognizerView.center recognizerView.center = CGPoint(x:originalCenter.x + translation.x, y:originalCenter.y + translation.y) // Inertia if inertia && recognizer.state == UIGestureRecognizerState.Ended { // Get speed let velocity = recognizer.velocityInView(parentView) let magnitude = min(sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y)) / 10000, 0.1) // Calculate final point var finalPoint = CGPoint( x:recognizerView.center.x + (velocity.x * magnitude), y:recognizerView.center.y + (velocity.y * magnitude)) // Consider bounds finalPoint.x = min(max(finalPoint.x, 0), parentView.bounds.size.width) finalPoint.y = min(max(finalPoint.y, 0), parentView.bounds.size.height) // Apply inertia animation UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {recognizerView.center = finalPoint }, completion: nil) } } // Reset recognizer translation recognizer.setTranslation(CGPointZero, inView: parentView) } }
ViewController
import UIKit import AVFoundation class ViewController: UIViewController { var ghostInitialPosition: CGPoint = CGPoint(); var player = AVAudioPlayer() @IBOutlet weak var ghostImage: UIImageView! override func viewDidLoad() { super.viewDidLoad() ghostInitialPosition = ghostImage.center } // Swipe @IBAction func onViewSwipe(recognizer: UISwipeGestureRecognizer) { print("swipe down") } // Tap @IBAction func onGhostTapped(sender: UITapGestureRecognizer) { playPunchSound() } // Rotate @IBAction func onGhostRotate(recognizer: UIRotationGestureRecognizer) { print("onGhostRotate \(recognizer.rotation)") // Apply gesture rotation to ghost view ghostImage.transform = CGAffineTransformRotate(ghostImage.transform, recognizer.rotation) // Reset recognizer rotation recognizer.rotation = 0 } // Panning @IBAction func onGhostPanning(recognizer: UIPanGestureRecognizer) { GestureHelper.applyGestureTranslationToGestureView(recognizer, parentView: self.view) } // Shake override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) { if event?.subtype == UIEventSubtype.MotionShake{ // Reset initial position ghostImage.center = ghostInitialPosition // Reset rotation and scale ghostImage.transform = CGAffineTransform() } } func playPunchSound(){ let audioPath = NSBundle.mainBundle().pathForResource("punch", ofType: "mp3")! do { // Initialize the player player = try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath)) // Play player.play() } catch{ print("Error creating audio player.") } } }