RxGesture for RxSwift Gesture Handling
RxSwift reactive wrapper for view gestures
At a glance
- What is it?
- RxGesture wraps UIKit and AppKit gesture recognizers in RxSwift observables, with typed APIs, state filtering, combined gestures, and delegate customization.
- Who is it for?
- RxGesture suits RxSwift applications that need gesture recognition to feed reactive UI code, especially when state filtering or combined gestures are useful. It is a poor fit for applications that do not use RxSwift or need gesture features outside the documented iOS and macOS APIs.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Where RxGesture Fits in an RxSwift Interface
RxGesture is a Swift library that connects UIKit and AppKit gesture recognizers to RxSwift. It is designed for developers who already use reactive subscriptions and want view interactions to follow the same event model as other interface logic. Instead of adding a recognizer, implementing its delegate, and forwarding each callback manually, an application can request a gesture through the view's `rx` property and subscribe to the resulting control event.
The documented basic case is a tappable view. The application requests `tapGesture()`, limits the stream to recognized taps, performs an action in `subscribe`, and binds the subscription's lifetime to an RxSwift disposal bag. This fits code that already organizes UI work around observable streams and resource disposal.
RxGesture does not create a new gesture vocabulary. It exposes recognizers already supplied by UIKit and AppKit, then adds an RxSwift-facing wrapper, filtering operators, combination helpers, and delegate configuration. Application logic still decides what a tap, pan, pinch, or rotation means. That boundary makes it a library for reactive integration rather than a complete interaction-design framework.
It is also not a general replacement for UIKit or AppKit gesture handling. Developers still need to understand recognizer states, simultaneous recognition, failure requirements, and platform-specific delegates. RxGesture makes those choices accessible from RxSwift configuration, but it does not remove the need to configure them correctly.
RxGesture Observables and Recognizer Types
The core `rx.gesture` property is documented as `Observable<G>`, where `G` is the actual gesture recognizer type. Its subscribers receive the recognizer itself rather than a generic event with no recognizer information. The README identifies methods such as `asLocation(in view:)` and `asTranslation(in view:)` as examples of calls that can be made on an emitted gesture.
On iOS, RxGesture exposes concrete APIs for taps, pinches, swipes, pans, long presses, rotations, screen-edge pans, and hover gestures. These methods return `ControlEvent` values typed with `UITapGestureRecognizer`, `UIPinchGestureRecognizer`, `UISwipeGestureRecognizer`, `UIPanGestureRecognizer`, `UILongPressGestureRecognizer`, `UIRotationGestureRecognizer`, `UIScreenEdgePanGestureRecognizer`, `UIHoverGestureRecognizer`, or the corresponding platform type. On macOS, the documented set covers clicks, right-clicks, pans, presses, rotations, and magnifications.
The concrete form should be preferred when an application observes one recognizer because it retains the subclass in the event type. The README explicitly notes that this avoids casting in a subscription. This matters when the handler needs recognizer-specific state or methods rather than merely using the event as a signal.
The broader `anyGesture()` API serves a different purpose. It combines multiple recognizers and returns a base gesture recognizer event type. That is convenient when several inputs should feed one subscription, but it sacrifices the concrete subtype available through the single-recognizer API.
Installing the Example and Filtering Tap State
The README directs developers to clone the repository, open `RxGesture.xcworkspace` in the `__Example__` folder, and run `pod install` from the Example directory if necessary. It describes opening the workspace as the route for running the example project, rather than requiring an application-wide setup call.
A first tap subscription can be built with the documented concrete API:
view.rx
.tapGesture()
.when(.recognized)
.subscribe(onNext: { _ in
//react to taps
})
.disposed(by: stepBag)The call creates a tap gesture event, `.when(.recognized)` removes unrelated states, and the subscription performs the tap action. Binding disposal to `stepBag` connects the subscription to the lifetime managed by the example's disposal bag.
The state filter is not cosmetic. Without one, the README says the stream includes a first event containing the initial recognizer state, usually `.possible`. A subscription intended for completed taps would therefore need to distinguish or exclude that initial state. The recommended filter for a tap is `.recognized`.
The repository includes example controllers for both supported platforms. The README points to `Example/RxGesture/ViewController.swift` for iOS and `Example/RxGesture-OSX/ViewController.swift` for macOS, describing them as examples for all supported recognizers.
Combining Taps, Swipes, and Other Input Paths
`anyGesture()` allows several recognizers to feed one subscription. The README's photo-preview example reacts when the user taps the preview or swipes upward or downward:
view.rx
.anyGesture(.tap(), .swipe([.up, .down]))
.when(.recognized)
.subscribe(onNext: { _ in
//dismiss presented photo
})
.disposed(by: stepBag)Here, `.when(.recognized)` applies one shared state requirement to every recognizer in the combined event. This works when each input reaches the same relevant state. It avoids separate subscriptions and keeps the dismissal behavior in one place.
Recognizers do not always share the same meaningful terminal state. RxGesture therefore documents tuple syntax for individual filters:
view.rx
.anyGesture(
(.tap(), when: .recognized),
(.pan(), when: .ended)
)
.subscribe(onNext: { gesture in
// Called whenever:
// - a tap is recognized (state == .recognized)
// - or a pan is ended (state == .ended)
})
.disposed(by: bag)This form reacts to recognized taps and ended pans while ignoring the other states of those recognizers. It is the relevant API when the application is combining distinct interaction models, such as a discrete tap with a continuous pan.
The trade-off is type precision. A combined event exposes the platform's base gesture recognizer type, whereas `tapGesture()` or `panGesture()` preserves the concrete recognizer. Shared subscriptions are simpler, but handlers that require subtype-specific behavior are better served by separate concrete streams.
Selecting Recognizer States for Each Interaction
Gesture recognizers emit state changes as interaction progresses, and RxGesture exposes `.when()` as the preferred filtering mechanism. For discrete gestures, the README lists `.recognized` as the preferred state for taps, clicks, right-clicks, and swipes. Press-oriented interactions use `.began` for long presses and presses.
Continuous gestures have several relevant states. For pans, pinches, rotations, magnifications, and screen-edge pans, the documented filter is `.began`, `.changed`, and `.ended`. Selecting only `.ended` can fit a one-time action such as committing a drag, while selecting all three states supports progress updates. Selecting only `.began` fits an action that begins when movement starts.
This makes state selection part of the interface contract rather than an incidental detail in a subscriber. A handler that expects only recognized taps should not rely on incidental filtering in its closure. A handler that reports pan progress should not subscribe to `.ended` alone.
RxGesture does not prescribe one universal policy for all gestures. The README presents state choices by recognizer kind, leaving the application to choose the event that matches its behavior. That flexibility is useful, but it means the state contract should be documented inside the feature code. Otherwise, a later state-filter change can silently alter when UI actions run.
Because the default stream includes an initial event, state filtering is particularly relevant during initial setup. It prevents setup events from being mistaken for completed user interactions.
Customizing RxGesture Delegate Policies
Each gesture recognizer created through RxGesture has a default `RxGestureRecognizerDelegate`. The configuration closure exposes that delegate so an application can change how its recognizer coordinates with touches, other recognizers, or system recognizers.
The documented policy values are `.always`, `.never`, and `.custom`. The first returns `true` for the corresponding delegate method, the second returns `false`, and the third invokes an associated closure to calculate the result. Available properties include `beginPolicy`, `touchReceptionPolicy`, `selfFailureRequirementPolicy`, `otherFailureRequirementPolicy`, `simultaneousRecognitionPolicy`, `eventRecognitionAttemptPolicy` on macOS, and `pressReceptionPolicy` on iOS.
The following configuration demonstrates the three documented forms for simultaneous recognition:
view.rx.tapGesture(configuration: { gestureRecognizer, delegate in
delegate.simultaneousRecognitionPolicy = .always
// or
delegate.simultaneousRecognitionPolicy = .never
// or
delegate.simultaneousRecognitionPolicy = .custom { gestureRecognizer, otherGestureRecognizer in
return otherGestureRecognizer is UIPanGestureRecognizer
}
})A custom policy allows coordination to depend on the other recognizer instead of applying one global decision. That can be useful when a tap and pan have different roles, although the application still owns the condition and must ensure it matches its interaction rules.
The delegate API is not identical across platforms. The README marks `eventRecognitionAttemptPolicy` as macOS-only and `pressReceptionPolicy` as iOS-only. Cross-platform code should isolate these assignments in the relevant platform implementation rather than assuming every property exists in both targets.
Package Integration, Licensing, and Release History
Based on the repository layout, RxGesture includes integration files for several Swift ecosystems: `Package.swift`, `RxGesture.podspec`, a `Cartfile`, and an `Example/Podfile`. The documented example workflow uses CocoaPods as a possible preparation step before opening `RxGesture.xcworkspace`. The README does not give a complete application-level installation command for Swift Package Manager, Carthage, or CocoaPods.
The release history records version 4.0.2 as a Carthage compatibility fix from 2021-03-24. Version 4.0.3, released on 2021-12-20, fixed Swift Package Manager compatibility. Version 4.0.4, released on 2022-03-24, fixed a build error on Xcode 13.3. These entries show attention to package-manager and build compatibility in specific releases, but they do not by themselves establish compatibility with every current Apple toolchain.
The repository is not archived, and its last push was on 2026-04-08. That is more recent than the latest listed release, but the README does not explain what changed in the default branch after version 4.0.4. An adopter comparing tags with the default branch should account for that gap.
The project uses the MIT license. Applications can review the repository's `LICENSE` file for its exact terms and notices. RxGesture also depends on RxSwift's reactive model, so adoption means evaluating both gesture integration and subscription ownership within the target application's disposal strategy.
Direct UIKit and AppKit Wiring Instead of RxGesture
The direct alternative is to add a UIKit or AppKit gesture recognizer, implement its delegate, and call application handlers from delegate callbacks. This approach uses only the platform framework and can be appropriate in a small application that does not use RxSwift. It also gives the developer direct access to recognizer state and delegate behavior without adding a reactive dependency.
RxGesture takes a different approach. It exposes platform recognizers as typed `ControlEvent` values, adds common state filters, supports combining several gesture sources, and connects subscriptions to an RxSwift disposal bag. The resulting code expresses an interaction as an observable stream rather than as a manually maintained callback target.
The direct approach can be simpler when there is one recognizer and one action. RxGesture becomes more useful when multiple gestures feed the same reactive logic, when a feature already follows a subscription-based architecture, or when state filtering should remain visible in the event pipeline. Its limitation is that applications must already accept RxSwift's abstraction and manage subscription lifetimes correctly.
A third option is a hand-written adapter that wraps UIKit and AppKit callbacks in application-specific RxSwift extensions. That can produce narrower event types or domain-specific values, but it duplicates work that RxGesture provides for standard recognizers. The README does not document such a project as an official alternative.
Editorial conclusion
RxGesture suits RxSwift applications that need gesture recognition to feed reactive UI code, especially when state filtering or combined gestures are useful. It is a poor fit for applications that do not use RxSwift or need gesture features outside the documented iOS and macOS APIs. Verify target-platform support, disposal ownership, and required delegate coordination before adoption. The latest listed release is 4.0.4, and the last push was on 2026-04-08.
Frequently asked questions
How do I install RxGesture?
The README directs users to clone the repository, open `RxGesture.xcworkspace` in the `__Example__` folder, and run `pod install` from the Example directory if needed. It does not provide a complete application-level installation command.
How do I react only to recognized taps with RxGesture?
Use `tapGesture()` and apply `.when(.recognized)` before subscribing. Without a state filter, the stream can include an initial event, usually with the `.possible` state.
Can RxGesture combine taps and swipes?
Yes. The README shows `anyGesture(.tap(), .swipe([.up, .down]))` with a shared `.recognized` filter, as well as tuple syntax for assigning different states to individual recognizers.
What is the difference between tapGesture and anyGesture in RxGesture?
A concrete API such as `tapGesture()` returns a `ControlEvent<UITapGestureRecognizer>` on iOS, preserving the recognizer subtype. `anyGesture()` returns a broader `UIGestureRecognizer` or `NSGestureRecognizer` type, making it convenient for combining recognizers but less precise for subtype-specific handling.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rxswiftcommunity-rxgesture)