UITapGestureRecognizer
touch down
touch up
iOS development
gesture recognizer

UITapGestureRecognizer - make it work on touch down, not touch up?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

UITapGestureRecognizer is designed to recognize a completed tap, which means it fires after the finger comes up, not when it first touches the screen. If you need immediate touch-down behavior, the real solution is usually to use a different API rather than trying to force a tap recognizer to behave like a press recognizer.

Why UITapGestureRecognizer Fires on Touch Up

A tap is not confirmed until UIKit knows the user actually performed a tap instead of starting a drag or long press. That decision requires the framework to observe the touch sequence through the release event.

For that reason, there is no supported setting that turns UITapGestureRecognizer into a touch-down recognizer.

Use UIControl Events for Buttons

If the view is a UIButton or another UIControl, the cleanest solution is to use .touchDown.

swift
1import UIKit
2
3final class ViewController: UIViewController {
4    private let button = UIButton(type: .system)
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8
9        button.setTitle("Press me", for: .normal)
10        button.addTarget(self, action: #selector(handleTouchDown), for: .touchDown)
11        button.frame = CGRect(x: 40, y: 120, width: 140, height: 44)
12        view.addSubview(button)
13    }
14
15    @objc private func handleTouchDown() {
16        print("Button touched down")
17    }
18}

This is the best option for controls because it matches UIKit's intended event model.

Use UILongPressGestureRecognizer with Zero Duration

For arbitrary views, a common workaround is UILongPressGestureRecognizer with minimumPressDuration = 0. It begins as soon as the finger touches down.

swift
1import UIKit
2
3final class ViewController: UIViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        let box = UIView(frame: CGRect(x: 40, y: 120, width: 140, height: 140))
8        box.backgroundColor = .systemBlue
9        view.addSubview(box)
10
11        let recognizer = UILongPressGestureRecognizer(
12            target: self,
13            action: #selector(handleImmediatePress(_:))
14        )
15        recognizer.minimumPressDuration = 0
16        recognizer.allowableMovement = 10
17        box.addGestureRecognizer(recognizer)
18    }
19
20    @objc private func handleImmediatePress(_ recognizer: UILongPressGestureRecognizer) {
21        if recognizer.state == .began {
22            print("Touch down on custom view")
23        }
24    }
25}

The important detail is checking for .began. A long-press recognizer continues to change state as the finger moves or lifts, so you do not want to trigger the action on every state update.

Use a Custom Recognizer Only When Necessary

If you need highly specific gesture semantics, you can subclass UIGestureRecognizer. That is usually overkill unless you are building a custom interaction that does not match UIKit's standard control or gesture APIs.

For many cases, the zero-duration long press is enough and is much easier to maintain.

Common Pitfalls

The biggest mistake is trying to keep UITapGestureRecognizer and expecting a property to switch it to touch down. That option does not exist because a tap is defined by a completed touch sequence.

Another issue is using UILongPressGestureRecognizer but forgetting to restrict the action to .began. If you respond on every state change, your code may fire multiple times for one finger press.

Gesture conflicts are also common. A press recognizer attached to a view inside a scroll view may compete with scrolling. In those cases, you may need delegate methods or a different interaction design.

Finally, if the target is really a button, do not bypass UIControl just to use a gesture recognizer. The built-in control events are simpler and map better to accessibility and UIKit conventions.

Summary

  • 'UITapGestureRecognizer recognizes taps on touch up, not touch down.'
  • Use .touchDown on UIControl subclasses such as UIButton.
  • For arbitrary views, UILongPressGestureRecognizer with minimumPressDuration = 0 is the usual touch-down substitute.
  • Trigger the long-press handler only when the recognizer state becomes .began.
  • Reach for a custom gesture recognizer only when standard UIKit tools do not fit the interaction.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.