Working with Tap Gesture Recognizers in Swift

Resources
Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy

Detecting gestures used to be tricky in the early days, but that changed with the introduction of the UIGestureRecognizer class in iOS 3.2. In this post, I show you how to use a tap gesture recognizer in Swift using the UITapGestureRecognizer class. We create a simple application and add a tap gesture recognizer to detect single and double taps.

Setting Up the Project in Xcode

Fire up Xcode and create a blank project by choosing the App template from the iOS > Application section.

Setting Up the Project in Xcode

Name the project Taps, set Interface to Storyboard, and Language to Swift.

Setting Up the Project in Xcode

Open ViewController.swift and declare an outlet with name tappableView of type UIView!. We use a didSet property observer to set the background color of the view to a bright red color. Using didSet property observers to configure outlets is a pattern I use a lot.

import UIKit

class ViewController: UIViewController {

    // MARK: - Properties

    @IBOutlet private var tappableView: UIView! {
        didSet {
            tappableView.backgroundColor = .red
        }
    }

    // MARK: - View Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

Open Main.storyboard, add a view to the view controller scene, and add constraints to center the view in the view controller's view. With the view selected, open the Connections Inspector on the right and connect the view to the outlet we defined in the ViewController class.

Creating the User Interface in Interface Builder

Build and run the application in a simulator. You should see a white view with a red view at its center.

Running the Application in the Simulator

Adding a Tap Gesture Recognizer to a View

We have two options to add a tap gesture recognizer to a view, in code or in Interface Builder. The result is identical, but the execution is different.

Adding a Tap Gesture Recognizer in Interface Builder

I never add gesture recognizers in Interface Builder, but that is a personal choice. By adding gesture recognizers in code, it is easier to understand how the view controller behaves by browsing its implementation. You don't need to switch between the code editor and Interface Builder.

Open Main.storyboard and drag a tap gesture recognizer from the Object Library and drop it onto the view we added earlier. The tap gesture recognizer appears in the Document Outline on the left.

We have added a tap gesture recognizer to the view, but we haven't attached an action to it. Open ViewController.swift and define an action. An action is another name for a method that is exposed to Interface Builder. The action accepts a single argument, the tap gesture recognizer.

// MARK: - Actions

@IBAction func didTapView(_ sender: UITapGestureRecognizer) {
    print("did tap view", sender)
}

Revisit Main.storyboard and select the tap gesture recognizer in the Document Outline. Open the Connections Inspector on the right and drag from selector in the Sent Actions section to the view controller in the Document Outline. A menu pops up that displays the didTapView(_:) action.

Connect the Action in Interface Builder

Connect the Action in Interface Builder

Build and run the application, tap the red view, and inspect the output in the console. The output confirms that we successfully added a tap gesture recognizer to the view.

didTapView(_:), 29, /Users/Bart/Desktop/Taps/Taps/ViewController.swift <UITapGestureRecognizer: 0x7ffc83508600; state = Ended; view = <UIView 0x7ffc74e0ab40>; target= <(action=didTapView:, target=<Taps.ViewController 0x7ffc835082a0>)>>

Adding a Tap Gesture Recognizer in Code

Remove the tap gesture recognizer in Interface Builder, revisit ViewController.swift, and navigate to the viewDidLoad() method. We initialize a UITapGestureRecognizer instance by invoking the init(target:action:) initializer. The target is the view controller and the action is the didTapView(_:) method we defined earlier.

// MARK: - View Life Cycle

override func viewDidLoad() {
    super.viewDidLoad()

    // Initialize Tap Gesture Recognizer
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapView(_:)))
}

// MARK: - Actions

@IBAction func didTapView(_ sender: UITapGestureRecognizer) {
    print("did tap view", sender)
}

We don't need to prefix the didTapView(_:) method with the IBAction attribute because we don't use Interface Builder to configure the tap gesture recognizer. If we remove the IBAction attribute, we need to prefix the didTapView(_:) method with the objc attribute instead. The objc attribute exposes the method to the Objective-C runtime. This is a more advanced topic that I won't cover in this post.

// MARK: - Actions

@objc func didTapView(_ sender: UITapGestureRecognizer) {
    print("did tap view", sender)
}

If we omit the objc attribute, the compiler throws an error.

We need to prefix the method with the objc attribute to expose it to the Objective-C runtime.

Before we can build and run the application, we need to add the tap gesture recognizer to the view. We invoke the addGestureRecognizer(_:) method on tappableView, passing in the tap gesture recognizer.

// MARK: - View Life Cycle

override func viewDidLoad() {
    super.viewDidLoad()

    // Initialize Tap Gesture Recognizer
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapView(_:)))

    // Add Tap Gesture Recognizer
    tappableView.addGestureRecognizer(tapGestureRecognizer)
}

Build and run the application one more time to make sure we didn't break anything. Tap the view and inspect the output in the console.

Detecting Double Taps With a Tap Gesture Recognizer In Swift

A tap gesture recognizer can detect single taps and double taps. Let's configure the tap gesture recognizer to detect double taps instead of single taps. In viewDidLoad(), we set the numberOfTapsRequired property of the tap gesture recognizer to 2. It defaults to 1.

// MARK: - View Life Cycle

override func viewDidLoad() {
    super.viewDidLoad()

    // Initialize Tap Gesture Recognizer
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapView(_:)))

    // Configure Tap Gesture Recognizer
    tapGestureRecognizer.numberOfTapsRequired = 2

    // Add Tap Gesture Recognizer
    tappableView.addGestureRecognizer(tapGestureRecognizer)
}

Build and run the application to test the change. Nothing is printed to the console if you tap the view once. The didTapView(_:) method is called if you tap the view twice. The output in the console confirms this. The UITapGestureRecognizer class encapsulates the logic for detecting single, double, and triple taps. Your task is limited to configuring the tap gesture recognizer.

Resources
Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy