You are here because you want to learn how to add a gesture recognizer to a UIImageView
instance. Right? In this post, I show you how to add a tap gesture recognizer to a UIImageView
instance. Even though we only add a tap gesture recognizer, what you learn in this post applies to swipe gestures, pan gestures, pinch gestures, ... Remember that UIImageView
is a subclass of UIView
and has the same capabilities as its superclass.
Some developers ask how to add a gesture recognizer to a UIImage
instance. That isn't possible. A UIImage
instance isn't part of the user interface of the application. An image is commonly displayed by a UIImageView
instance, which means we add a gesture recognizer to the image view (UIImageView
), not the image (UIImage
).
Setting Up the Project in Xcode
Fire up Xcode and create a blank project by choosing the App template from the iOS > Application section.
Name the project Tappable, set Interface to Storyboard, and Language to Swift.
Add a few images to the asset catalog of the project. You can use any image you want.
Open ViewController.swift and declare an outlet with name imageView
of type UIImageView!
. We use a didSet
property observer to set the image
property of the image view. Using didSet
property observers to configure outlets is a pattern I use a lot.
import UIKit
class ViewController: UIViewController {
// MARK: - Properties
@IBOutlet private var imageView: UIImageView! {
didSet {
imageView.image = UIImage(named: "landscape")
}
}
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
}
}
Open Main.storyboard, add a UIImageView
instance to the view controller scene, and add constraints to center the image 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.
Build and run the application in a simulator. You should see a white view with an image view at its center.
Adding a Tap Gesture Recognizer to an Image View
You can add a gesture recognizer in code or in Interface Builder. I always add gesture recognizers in code, but that is a personal choice. Let's start with Interface Builder.
Adding a Tap Gesture Recognizer to an Image View in Interface Builder
Open Main.storyboard and drag a tap gesture recognizer from the Object Library and drop it onto the image view we added earlier. The tap gesture recognizer appears in the Document Outline on the left.
We need to implement an action that defines what happens when the user taps the image view. Open ViewController.swift and define a method with name didTapImageView(_:)
. It accepts the tap gesture recognizer as its only argument.
// MARK: - Actions
@IBAction func didTapImageView(_ sender: UITapGestureRecognizer) {
print("did tap image view", sender)
}
Open 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 didTapImageView(_:)
action.
Build and run the application in a simulator and tap the image view. Press Command + Shift + Y to open the console at the bottom. The console is blank, which means that the tap gesture recognizer isn't detecting any taps in the image view. Something isn't right.
The solution to this problem is easy, though. A view can only respond to user interaction if its isUserInteractionEnabled
property is set to true
. true
is the default value of a UIView
instance. For a UIImageView
instance, the default value is false
. That is what trips up many developers.
Revisit the didSet
property observer of imageView
and set its isUserInteractionEnabled
property to true
. We update the property in code, but you can make this change in Interface Builder if you prefer that. Build and run the application to verify that the issue is resolved and the image view receives taps.
import UIKit
class ViewController: UIViewController {
// MARK: - Properties
@IBOutlet private var imageView: UIImageView! {
didSet {
imageView.isUserInteractionEnabled = true
imageView.image = UIImage(named: "landscape")
}
}
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Actions
@IBAction func didTapImageView(_ sender: UITapGestureRecognizer) {
print("did tap image view", sender)
}
}
did tap image view <UITapGestureRecognizer: 0x133e09230; state = Ended; view = <UIImageView 0x133e06380>; target= <(action=didTapImageView:, target=<Tappable.ViewController 0x133e0a490>)>>
Adding a Tap Gesture Recognizer to an Image View in Code
Open Main.storyboard and remove the tap gesture recognizer from the image view. Navigate to the viewDidLoad()
method of the ViewController
class. To initialize a UITapGestureRecognizer
instance, we invoke the init(target:action:)
initializer. The target is the view controller and the action is the didTapViewImageView(_:)
method.
import UIKit
class ViewController: UIViewController {
// MARK: - Properties
@IBOutlet private var imageView: UIImageView! {
didSet {
imageView.isUserInteractionEnabled = true
imageView.image = UIImage(named: "landscape")
}
}
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// Initialize Tap Gesture Recognizer
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapImageView(_:)))
}
// MARK: - Actions
@IBAction func didTapImageView(_ sender: UITapGestureRecognizer) {
print("did tap image view", sender)
}
}
We can remove the IBAction
attribute from didTapImageView(_:)
since we no longer use Interface Builder to set up the tap gesture recognizer. If we remove the IBAction
attribute, the compiler throws an error.
We need to prefix didTapImageView(_:)
wit the objc
attribute to expose it to the Objective-C runtime. This is a more advanced topic that I won't cover in this post.
// MARK: - Actions
@objc private func didTapImageView(_ sender: UITapGestureRecognizer) {
print("did tap image view", sender)
}
In the viewDidLoad()
method, we invoke addGestureRecognizer(_:)
on imageView
, passing in the tap gesture recognizer, to add the tap gesture recognizer to imageView
.
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// Initialize Tap Gesture Recognizer
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapImageView(_:)))
// Add Tap Gesture Recognizer
imageView.addGestureRecognizer(tapGestureRecognizer)
}
Let's build and run the application to make sure the image view still responds to taps. Tap the image view and press Command + Shift + Y to inspect the output in the console.
Don't Forget isUserInteractionEnabled
The most common mistake developers make when working with UIImageView
is not setting isUserInteractionEnabled
to true
. A view with isUserInteractionEnabled
set to false
ignores touches from the user. The touches pass through the view to the view beneath it.