iOS
UIGestureRecognizer
Touch Events
Subview
Mobile Development

UIGestureRecognizer blocks subview for handling touch events

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

A gesture recognizer attached to a parent view can prevent a subview from receiving touch events if the recognizer cancels or delays delivery. This is not usually a bug in UIKit. It is a consequence of how hit testing, gesture recognition, and the responder chain work together.

Why a Parent Gesture Can Interfere With a Subview

When the user touches the screen, UIKit finds the deepest view that should receive the touch through hit testing. Gesture recognizers attached to views in that hierarchy also observe the touch stream. If a recognizer decides it has matched its gesture, it can cancel touches that were on their way to the view.

That is why a tap recognizer on a container view may appear to block a button inside the container. The recognizer is not stealing the touch at random. It is participating in the same event flow and may be configured to cancel touches in the view once recognition succeeds.

The First Property to Check

For many cases, the most important property is cancelsTouchesInView.

swift
1import UIKit
2
3final class DemoViewController: UIViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
8        tap.cancelsTouchesInView = false
9        view.addGestureRecognizer(tap)
10    }
11
12    @objc private func handleTap() {
13        print("Container tapped")
14    }
15}

Setting cancelsTouchesInView to false tells UIKit not to cancel the view's touch delivery when the recognizer succeeds. That is often enough when the parent view should recognize taps but subviews such as buttons should still work normally.

Filter Touches With a Delegate

Sometimes you do not want the parent recognizer to handle touches that begin on certain subviews at all. In that case, use a gesture recognizer delegate.

swift
1import UIKit
2
3final class DemoViewController: UIViewController, UIGestureRecognizerDelegate {
4    @IBOutlet private weak var actionButton: UIButton!
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8
9        let tap = UITapGestureRecognizer(target: self, action: #selector(handleBackgroundTap))
10        tap.delegate = self
11        view.addGestureRecognizer(tap)
12    }
13
14    @objc private func handleBackgroundTap() {
15        print("Background tapped")
16    }
17
18    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
19                           shouldReceive touch: UITouch) -> Bool {
20        return touch.view !== actionButton
21    }
22}

This lets the button keep exclusive control of its own touches while the background recognizer handles the rest of the view.

Allow Multiple Recognizers When Appropriate

If two gestures should be recognized together, implement the simultaneous-recognition delegate method.

swift
1func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
2                       shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
3    return true
4}

Use this carefully. Simultaneous recognition is helpful for compatible gestures, but it can also make behavior harder to reason about if every recognizer is allowed to succeed together.

Attach the Recognizer at the Right Level

Sometimes the cleanest fix is architectural. If only the empty background should respond to taps, attach the recognizer to a background view rather than to the whole container. That reduces conflict with interactive subviews and removes the need for complex delegate rules.

A recognizer placed too high in the hierarchy usually has to spend the rest of its life being told which touches to ignore.

Common Pitfalls

A common mistake is assuming isUserInteractionEnabled on the subview is the only thing that matters. A subview can be fully interactive and still lose touches because a recognizer higher in the tree cancels them.

Another mistake is setting cancelsTouchesInView to false and expecting all conflicts to disappear. That property helps, but it does not replace good recognizer placement or delegate filtering.

Developers also sometimes attach broad tap recognizers to views that already contain many controls. In those cases, delegate logic becomes complex quickly. A narrower attachment point is usually cleaner.

Summary

  • Parent gesture recognizers participate in the same touch stream as subviews.
  • A recognizer can block subview handling by canceling or delaying touches.
  • Start by checking cancelsTouchesInView.
  • Use a delegate to ignore touches on specific subviews when needed.
  • Put recognizers at the lowest sensible view in the hierarchy to minimize conflicts.

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.