Many controls such as table views, map views, scroll views and buttons use gestures. You as a developer might want to use a gesture for your own purposes outside of these controls. The gesture recognizer classes can do that. The standard ones such a as tap, pinch and rotate are rather easy to set up, either by storyboard or by code. In this tutorial, I’ll show you how to set them up in code.
Set Up the Project
Make a new single view project called TapPinchDemo in Swift with a Universal device. Go to the storyboard. Add a label to the upper left of the storyboard. I used auto layout to pin the label 10up, 10 left and 10 right. Change the label’s font to Title.
Open the assistant editor. Control drag from the label to the code and make an outlet named statusLabel. Close the assistant editor and go to the ViewController.swift code. Add a constant at the beginning of the ViewController
class for a color.
let background = UIColor(red: 1.0, green: 0.98, blue: 0.96, alpha: 1.0)
In viewDidLoad
add this color as the background.
override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = background }
Tap Gestures
There are three parts to a gesture: Configuring a gesture recognizer object, making an action for the object, and adding it to the view. For the first gesture, you’ll make a tap gesture. In viewDidLoad
add the following line to make a tap gesture:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAction(sender:)))
There’s two parameters in the constructor. Both indicate the location of an action that will be called when the gesture occurs. the first give the class, and the second the selector. selectors are functions called by the parameters of another function. While really a Objective-C thing, Swift had a compiler tag #selector()
to indicate a selector. In the tap gesture tapAction(selector:)
is the function called.
You’ll notice an error. Once you use a #selector
, you must implement the function. Add the function tapAction
above viewDidLoad
func tapAction(sender:UITapGestureRecognizer){ }
We’ll come back in a minute to finish filling out this code. Go back to viewDidLoad
and configure tapGesture
.
tapGesture.numberOfTapsRequired = 1 tapGesture.numberOfTouchesRequired = 1
This sets the gesture recognizer to one tap with one finger. Add the gesture recognizer to the view using the addGestureRecognizer
method.
view.addGestureRecognizer(tapGesture)
Go back up to the function tapAction
. Gestures have states. You must check the state before you do anything. Specific states are necessary for specific gestures to work. For a tap, the state must be .ended
. Add this code to the tap action selector:
if sender.state == .ended{ statusLabel.text = "Tapped" view.backgroundColor = background }
Build and run. Tap the screen and the label reads tapped.
Pinch Gesture
The pinch gesture is a movement of two fingers moving towards or away from eacth other. Pinch gestures have no properties you need to set. Adding them is even easier than a tap. Just call the UIPinchGestureRecognizer
constructor and add the gesture recognizer to the view. Add this to viewDidLoad
.
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchAction(sender:))) view.addGestureRecognizer(pinchGesture)
The action specified is a bit more complex than the tap. You have three states you might want to look at: .began
, .changed
, and .ended
. Most often your concern is the changed state which occurs when a user moves his or her fingers. But you might find uses for beginning and ending a pinch. Add the following method to the ViewController
code.
func pinchAction(sender:UIPinchGestureRecognizer){ if sender.state == .began{ statusLabel.text = "Pinch Began" view.backgroundColor = UIColor.yellow } if sender.state == .changed{ statusLabel.text = String(format:"Pinch scale: %1.3f",sender.scale) } if sender.state == .ended{ statusLabel.text = "Pinch Ended" view.backgroundColor = background } }
Pinches are examples of continuous gestures. These are gestures which will have more than one state to watch for. This changes the background when you have started the pinch and restores when you finish the pinch. When you change the value, it shows the scale value for the gesture. Scale is a value that shows the change between the user’s first pinch and the movement of the user’s fingers. Scale is the value you use in your applications. Build and run. Try pinching the screen. In the simulator, hold down the option key and drag on the trackpad or mouse.
Rotation Gesture
The last gesture we’ll discuss is rotation. Rotations set up just like pinches, except they use a UIRotationGestureRecognizer
constructor. Add this to viewDidLoad
:
let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotateAction(sender:))) view.addGestureRecognizer(rotateGesture)
And add this function for the action. Like pinch, rotate is a continuous gesture, so I’ll set it up similar to pinchAction
.
func rotateAction(sender:UIRotationGestureRecognizer){ if sender.state == .began{ statusLabel.text = "Rotate Began" view.backgroundColor = UIColor.cyan } if sender.state == .changed{ statusLabel.text = String(format:"rotation: %1.3f",sender.rotation) } if sender.state == .ended{ statusLabel.text = "Rotate Ended" view.backgroundColor = background } }
The code will turn the background cyan when the user starts a rotate action. The display will give the rotation angle in radians using the property of a rotator gesture rotation
. When the rotation ends with the user removing fingers, the background returns to the default background color. Build and run. To simulate a rotation click down on the simulator using the mouse and then press Option(it’s annoyingly tricky). Move the cursor and you will have a rotation gesture.
This is only the beginning to using gestures, but should give you a good foundation for other gestures. While I most often use code to add gestures, you can also add then by dragging them onto the storyboard. Once added, you find them in the document outline, where you can control drag them to the code like any other object and make an action. Gestures my also conflict with each other, so try to keep the number in a single view to a minimum.
The Whole Code
// // ViewController.swift // tapSwipeDemo // // Created by Steven Lipton on 11/25/16. // Copyright © 2016 Steven Lipton. All rights reserved. // import UIKit class ViewController: UIViewController { @IBOutlet weak var statusLabel: UILabel! let background = UIColor(red: 1.0, green: 0.98, blue: 0.96, alpha: 1.0) func tapAction(sender:UITapGestureRecognizer){ if sender.state == .ended{ statusLabel.text = "Tapped" view.backgroundColor = background } } func pinchAction(sender:UIPinchGestureRecognizer){ if sender.state == .began{ statusLabel.text = "Pinch Began" view.backgroundColor = UIColor.yellow } if sender.state == .changed{ statusLabel.text = String(format:"Pinch scale: %1.3f",sender.scale) } if sender.state == .ended{ statusLabel.text = "Pinch Ended" view.backgroundColor = background } } func rotateAction(sender:UIRotationGestureRecognizer){ if sender.state == .began{ statusLabel.text = "Rotate Began" view.backgroundColor = UIColor.cyan } if sender.state == .changed{ statusLabel.text = String(format:"rotation: %1.3f",sender.rotation) } if sender.state == .ended{ statusLabel.text = "Rotate Ended" view.backgroundColor = background } } func swipeAction(sender:UISwipeGestureRecognizer){ if sender.state == .began{ statusLabel.text = "Swipe!" } } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = background let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAction(sender:))) tapGesture.numberOfTapsRequired = 1 tapGesture.numberOfTouchesRequired = 1 view.addGestureRecognizer(tapGesture) let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchAction(sender:))) view.addGestureRecognizer(pinchGesture) let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotateAction(sender:))) view.addGestureRecognizer(rotateGesture) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
Leave a Reply