RxGesture

repository·main·Indexed 23 days ago

https://github.com/rxswiftcommunity/rxgesture

A library providing reactive extensions for gesture recognizers in RxSwift for iOS and macOS. It allows developers to turn views into tappable or swipeable controls using a declarative syntax, featuring support for single or multiple gestures via anyGesture, state filtering with .when(), and customizable gesture delegate policies.

Tokens
2.3K
Snippets
7
Records
8
Agent score
30%

What's inside RxGesture

  1. Filter gesture states using .when()

    main

    By default, RxGesture emits events for all states (including .possible). To react only to specific lifecycle stages of a gesture, use the .when() operator.

    Recommended states by gesture type:

    • .tap(), .click(), .rightClick(), .swipe(): Use .recognized
    • .longPress(), .press(): Use .began
    • .pan(), .pinch(), .rotation(), .magnification(), .screenEdgePan(): Use .began, .changed, or .ended

    When using anyGesture, you can apply a single state filter to all gestures in the group, or use tuple syntax to apply different filters to each gesture.

  2. Use RxGesture to handle single or multiple gestures

    main

    RxGesture allows you to turn any view into a reactive control. You can use specific gesture methods for a single gesture or anyGesture to react to multiple types of gestures simultaneously.

    Note: Using specific methods like tapGesture() is preferred over anyGesture(.tap()) because they return the concrete subclass (e.g., UITapGestureRecognizer), avoiding the need for manual type casting in your subscription.

    // Single gesture
    view.rx
      .tapGesture()
      .when(.recognized)
      .subscribe(onNext: { _ in
        // react to taps
      })
      .disposed(by: stepBag)
    
    // Multiple gestures
    view.rx
      .anyGesture(.tap(), .swipe([.up, .down]))
      .when(.recognized)
      .subscribe(onNext: { _ in
        // dismiss presented photo
      })
      .disposed(by: stepBag)
  3. macOS Gesture Recognizer API

    main

    RxGesture provides the following ControlEvent mappings for macOS views.

    view.rx.clickGesture()         -> ControlEvent<NSClickGestureRecognizer>
    view.rx.rightClickGesture()    -> ControlEvent<NSClickGestureRecognizer>
    view.rx.panGesture()           -> ControlEvent<NSPanGestureRecognizer>
    view.rx.pressGesture()         -> ControlEvent<NSPressGestureRecognizer>
    view.rx.rotationGesture()      -> ControlEvent<NSRotationGestureRecognizer>
    view.rx.magnificationGesture() -> ControlEvent<NSMagnificationGestureRecognizer>
    
    // Multi-gesture variants return the base class
    view.rx.anyGesture(.click(), ...)         -> ControlEvent<NSGestureRecognizer>
    view.rx.anyGesture(.rightClick(), ...)    -> ControlEvent<NSGestureRecognizer>
    view.rx.anyGesture(.pan(), ...)           -> ControlEvent<NSGestureRecognizer>
    view.rx.anyGesture(.press(), ...)         -> ControlEvent<NSGestureRecognizer>
    view.rx.anyGesture(.rotation(), ...)      -> ControlEvent<NSGestureRecognizer>
    view.rx.anyGesture(.magnification(), ...) -> ControlEvent<NSGestureRecognizer>
  4. iOS Gesture Recognizer API

    main

    RxGesture provides the following ControlEvent mappings for iOS views. These return concrete gesture recognizer subclasses.

    view.rx.tapGesture()           -> ControlEvent<UITapGestureRecognizer>
    view.rx.pinchGesture()         -> ControlEvent<UIPinchGestureRecognizer>
    view.rx.swipeGesture(.left)    -> ControlEvent<UISwipeGestureRecognizer>
    view.rx.panGesture()           -> ControlEvent<UIPanGestureRecognizer>
    view.rx.longPressGesture()     -> ControlEvent<UILongPressGestureRecognizer>
    view.rx.rotationGesture()      -> ControlEvent<UIRotationGestureRecognizer>
    view.rx.screenEdgePanGesture() -> ControlEvent<UIScreenEdgePanGestureRecognizer>
    view.rx.hoverGesture()         -> ControlEvent<UIHoverGestureRecognizer>
    
    // Multi-gesture variants return the base class
    view.rx.anyGesture(.tap(), ...)           -> ControlEvent<UIGestureRecognizer>
    view.rx.anyGesture(.pinch(), ...)         -> ControlEvent<UIGestureRecognizer>
    view.rx.anyGesture(.swipe(.left), ...)    -> ControlEvent<UIGestureRecognizer>
    view.rx.anyGesture(.pan(), ...)           -> ControlEvent<UIGestureRecognizer>
    view.rx.anyGesture(.longPress(), ...)     -> ControlEvent<UIGestureRecognizer>
    view.rx.anyGesture(.rotation(), ...)      -> ControlEvent<UIGestureRecognizer>
    view.rx.anyGesture(.screenEdgePan(), ...) -> ControlEvent<UIGestureRecognizer>
    view.rx.anyGesture(.hover(), ...)         -> ControlEvent<UIGestureRecognizer>
  5. Customize gesture delegate policies

    main

    You can customize the behavior of the RxGestureRecognizerDelegate using a configuration closure. This allows you to control how gestures interact with each other or how they receive touches.

    Available Policies:

    • .always: Returns true for the delegate method.
    • .never: Returns false for the delegate method.
    • .custom: Takes a closure (gestureRecognizer, ...) -> Bool to return a custom value.

    Available Delegate Methods (via policies):

    • beginPolicy -> gestureRecognizerShouldBegin(_:)
    • touchReceptionPolicy -> gestureRecognizer(_:shouldReceive:)
    • selfFailureRequirementPolicy -> gestureRecognizer(_:shouldBeRequiredToFailBy:)
    • otherFailureRequirementPolicy -> gestureRecognizer(_:shouldRequireFailureOf:)
    • simultaneousRecognitionPolicy -> gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)
    • eventRecognitionAttemptPolicy -> gestureRecognizer(_:shouldAttemptToRecognizeWith:) (macOS only)
    • pressReceptionPolicy -> gestureRecognizer(_:shouldReceive:) (iOS only)
    view.rx.tapGesture(configuration: { gestureRecognizer, delegate in
      delegate.simultaneousRecognitionPolicy = .always
      // or
      delegate.simultaneousRecognitionPolicy = .custom { gestureRecognizer, otherGestureRecognizer in
        return otherGestureRecognizer is UIPanGestureRecognizer
      }
      delegate.otherFailureRequirementPolicy = .custom { gestureRecognizer, otherGestureRecognizer in
        return otherGestureRecognizer is UILongPressGestureRecognizer
      }
    })
  6. Replace or remove the gesture delegate

    main

    For full control, you can replace the default RxGestureRecognizerDelegate with your own delegate or remove it entirely within the configuration closure.

    view.rx.tapGesture { [unowned self] gestureRecognizer, delegate in
      gestureRecognizer.delegate = nil
      // or
      gestureRecognizer.delegate = self
    }