UIPanGestureRecognizer
iOS development
gesture recognition
vertical pan
horizontal pan

UIPanGestureRecognizer - Only vertical or horizontal

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

UIPanGestureRecognizer reports free-form movement, but many interfaces need directional locking so interactions behave as either vertical or horizontal only. Typical examples include sliders, drawer menus, and sortable lists where diagonal movement should be ignored. A clean solution determines dominant axis early in the gesture, then constrains subsequent translation to that axis. This avoids jitter and keeps UI behavior predictable. You can implement this in gesture handling logic without custom recognizer subclasses, though subclassing can help if many views share the same rule.

Core Sections

Determine dominant axis at gesture start

Use initial translation velocity or movement delta to lock direction.

swift
1enum PanAxis { case horizontal, vertical }
2
3final class AxisLockedPanController {
4    var axis: PanAxis?
5
6    func updateAxisIfNeeded(_ pan: UIPanGestureRecognizer, in view: UIView) {
7        guard axis == nil else { return }
8        let velocity = pan.velocity(in: view)
9        axis = abs(velocity.x) > abs(velocity.y) ? .horizontal : .vertical
10    }
11
12    func reset() { axis = nil }
13}

Velocity-based locking usually feels responsive in UI interactions.

Constrain translation according to locked axis

Apply only relevant component to your target transform or frame.

swift
1let lock = AxisLockedPanController()
2
3@objc func handlePan(_ pan: UIPanGestureRecognizer) {
4    guard let view = pan.view else { return }
5    lock.updateAxisIfNeeded(pan, in: view.superview ?? view)
6
7    let t = pan.translation(in: view.superview)
8    switch lock.axis {
9    case .horizontal:
10        view.center.x += t.x
11    case .vertical:
12        view.center.y += t.y
13    case .none:
14        break
15    }
16    pan.setTranslation(.zero, in: view.superview)
17
18    if pan.state == .ended || pan.state == .cancelled || pan.state == .failed {
19        lock.reset()
20    }
21}

Reset axis at end so each new gesture can decide independently.

Use delegate rules for recognizer coordination

If panning competes with scroll views, implement recognizer delegate methods to avoid conflicts.

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

For nested scroll interactions, you may allow simultaneous recognition conditionally.

Add threshold to prevent accidental lock

Tiny initial movement noise can cause wrong direction lock. Add minimum displacement before locking.

swift
let minLockDistance: CGFloat = 8
if abs(translation.x) + abs(translation.y) < minLockDistance { return }

This improves feel on high-sensitivity screens.

Test with real devices

Simulator input can differ from actual touch behavior. Validate on device with fast and slow swipes, one-handed interactions, and edge cases near screen boundaries.

Common Pitfalls

  • Locking axis immediately on tiny jitter, resulting in erratic direction choices.
  • Forgetting to reset lock state when gesture ends, causing next gesture to inherit stale axis.
  • Applying both x and y deltas after deciding axis, which defeats directional constraint.
  • Ignoring competition with scroll views and getting inconsistent gesture ownership.
  • Validating only in simulator and missing real-device touch dynamics.

Verification Workflow

After implementing the main approach, run a short verification loop that proves behavior on realistic and adversarial inputs. Start with a small happy-path sample that should always pass, then add one edge case and one failure case that should be rejected or handled gracefully. Capture concrete outputs instead of relying on visual inspection alone. For operational code, record one measurable signal such as runtime, memory use, or error count so you can compare before and after future refactors.

Use this quick template during local development and CI:

text
11. Prepare deterministic sample input
22. Run expected-success scenario
33. Run expected-edge scenario
44. Run expected-failure scenario
55. Assert output schema and key values
66. Record one performance or reliability metric

This discipline catches most regressions caused by dependency upgrades, environment differences, or hidden assumptions in helper functions. It also makes handoffs easier because another engineer can reproduce behavior quickly without reverse-engineering your intent from source code alone.

Summary

To make UIPanGestureRecognizer vertical-only or horizontal-only, detect dominant axis early, lock it, and apply constrained translation throughout the gesture. Add a small movement threshold and reset lock state reliably at gesture completion. Coordinate with other recognizers through delegate rules for stable interaction behavior. This approach yields smooth, intentional gesture UX without heavy custom gesture infrastructure.


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.