UIGestureRecognizer Tutorial: Getting Started

In this tutorial, you’ll learn how to configure UIGestureRecognizer objects and how to create custom recognizers in code. By Ryan Ackermann.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Managing the Gesture’s State

One of the things that you’ll change is the state of the gesture. When a tickle completes, you’ll change the state of the gesture to ended.

Switch to TickleGestureRecognizer.swift and add the following methods to the class:

override func reset() {
  tickleCount = 0
  latestDirection = .unknown
  tickleStartLocation = .zero

  if state == .possible {
    state = .failed
  }
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
  guard let touch = touches.first else {
    return
  }

  tickleStartLocation = touch.location(in: view)
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
  guard let touch = touches.first else {
    return
  }

  let tickleLocation = touch.location(in: view)

  let horizontalDifference = tickleLocation.x - tickleStartLocation.x

  if abs(horizontalDifference) < distanceForTickleGesture {
    return
  }

  let direction: TickleDirection

  if horizontalDifference < 0 {
    direction = .left
  } else {
    direction = .right
  }

  if latestDirection == .unknown ||
    (latestDirection == .left && direction == .right) ||
    (latestDirection == .right && direction == .left) {

    tickleStartLocation = tickleLocation
    latestDirection = direction
    tickleCount += 1

    if state == .possible && tickleCount > requiredTickles {
      state = .ended
    }
  }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
  reset()
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
  reset()
}

There’s a lot of code here and you don’t need to know the specifics for this tutorial.

To give you a general idea of how it works, you’re overriding the UIGestureRecognizer‘s reset(), touchesBegan(_:with:), touchesMoved(_:with:), touchesEnded(_:with:) and touchesCancelled(_:with:) methods. And you’re writing custom code to look at the touches and detect the gesture.

Once you’ve found the gesture, you’ll want to send updates to the callback method. You do this by changing the state property of the gesture recognizer.

Once the gesture begins, you’ll usually set the state to .began. After that, you’ll send any updates with .changed and finalize it with .ended.

For this simple gesture recognizer, once the user has tickled the object, that’s it. You’ll just mark it as .ended.

OK, now to use this new recognizer!

Implementing Your Custom Recognizer

Open ViewController.swift and make the following changes.

Add the following code to the top of the class, right after chompPlayer:

private var laughPlayer: AVAudioPlayer?

In viewDidLoad(), add the gesture recognizer to the image view by replacing the TODO:

let tickleGesture = TickleGestureRecognizer(
  target: self,
  action: #selector(handleTickle)
)
tickleGesture.delegate = self
imageView.addGestureRecognizer(tickleGesture)

At end of viewDidLoad() add:

laughPlayer = createPlayer(from: "laugh")

Finally, create a new method at the end of the class to handle your tickle gesture:

@objc func handleTickle(_ gesture: TickleGestureRecognizer) {
  laughPlayer?.play()
}

Using this custom gesture recognizer is as simple as using the built-in ones!

Build and run. “Hehe, that tickles!”

Testing the tickle gesture recognizer

Where to Go From Here?

Download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.

Congrats, you’re now a master of gesture recognizers — both built-in and custom ones! Touch interaction is such an important part of iOS devices and UIGestureRecognizer is the key to adding easy-to-use gestures beyond simple button taps.

I hope you enjoyed this tutorial! If you have any questions or comments, please join the discussion below.