Skip to content

Gestures

Native-backed gesture recognition, attached to any view-like element via the gestures= prop. Descriptors are frozen dataclasses; their numeric configuration crosses the bridge while callbacks are routed through the tag-based event channel. See the Gestures guide for usage patterns.

Native-backed gesture system.

Attach gestures to any view-like element via the gestures= prop:

import pythonnative as pn
from pythonnative import gestures


@pn.component
def Draggable():
    tx = pn.use_animated_value(0.0)
    ty = pn.use_animated_value(0.0)

    def on_pan(event):
        tx.set_value(event.translation_x)
        ty.set_value(event.translation_y)

    def on_end(event):
        pn.Animated.spring(tx, to=0.0).start()
        pn.Animated.spring(ty, to=0.0).start()

    return pn.Animated.View(
        pn.Text("Drag me"),
        style={"transform": [{"translate_x": tx}, {"translate_y": ty}], "padding": 24},
        gestures=[gestures.Pan(on_change=on_pan, on_end=on_end)],
    )

Each gesture descriptor is a frozen dataclass holding numeric configuration plus user callbacks. The reconciler serializes the configuration into plain dicts for the native handler (so prop diffing never compares closures) and routes the callbacks through the tag-based event channel. Recognition itself is native:

  • iOS attaches real UIGestureRecognizer instances.
  • Android feeds raw MotionEvent streams into the pure-Python GestureArbiter below.
  • Desktop feeds Tk pointer events into the same arbiter.

All gestures attached to one view recognize simultaneously; there is no cross-gesture exclusivity arbitration yet.

Every callback receives a GestureEvent with position, translation, velocity, scale, and rotation populated as appropriate for the gesture kind.

Classes:

Name Description
GestureState

States reported on GestureEvent.state.

GestureEvent

Snapshot delivered to gesture callbacks.

Tap

Recognize n_taps quick taps.

LongPress

Recognize a sustained press.

Pan

Track a drag with translation and velocity.

Swipe

Recognize a quick directional flick.

Pinch

Track a two-finger pinch; event.scale is relative to activation.

Rotation

Track a two-finger rotation; event.rotation is in radians.

GestureArbiter

Turn a raw pointer-event stream into gesture event payloads.

Functions:

Name Description
serialize_gestures

Split gesture descriptors into native config dicts and event routers.

GestureStateName module-attribute

GestureStateName = Literal['began', 'changed', 'ended', 'cancelled']

GestureCallback module-attribute

GestureCallback = Callable[['GestureEvent'], None]

SwipeDirection module-attribute

SwipeDirection = Literal['any', 'left', 'right', 'up', 'down']

GestureSpec module-attribute

GestureSpec = _BaseGesture

Any gesture descriptor accepted by the gestures= prop.

EmitFn module-attribute

EmitFn = Callable[[int, Dict[str, Any]], None]

emit(gesture_index, payload): the arbiter's output channel.

GestureState

States reported on GestureEvent.state.

Attributes:

Name Type Description
BEGAN
CHANGED
ENDED
CANCELLED

BEGAN class-attribute instance-attribute

BEGAN = 'began'

CHANGED class-attribute instance-attribute

CHANGED = 'changed'

ENDED class-attribute instance-attribute

ENDED = 'ended'

CANCELLED class-attribute instance-attribute

CANCELLED = 'cancelled'

GestureEvent dataclass

GestureEvent(kind: str, state: GestureStateName, x: float = 0.0, y: float = 0.0, translation_x: float = 0.0, translation_y: float = 0.0, velocity_x: float = 0.0, velocity_y: float = 0.0, scale: float = 1.0, rotation: float = 0.0, pointer_count: int = 1, direction: Optional[str] = None)

Snapshot delivered to gesture callbacks.

Attributes:

Name Type Description
kind str

Gesture kind ("tap", "long_press", "pan", "swipe", "pinch", "rotation").

state GestureStateName

One of GestureState.

x float

Pointer x-position in the view's coordinate space (points).

y float

Pointer y-position in the view's coordinate space (points).

translation_x float

Horizontal displacement since the gesture activated (pan only).

translation_y float

Vertical displacement since the gesture activated (pan only).

velocity_x float

Horizontal pointer velocity in points/second (pan and swipe).

velocity_y float

Vertical pointer velocity in points/second (pan and swipe).

scale float

Pinch scale factor relative to activation (pinch only).

rotation float

Rotation in radians relative to activation (rotation only).

pointer_count int

Number of pointers currently down.

direction Optional[str]

Resolved swipe direction (swipe only).

kind instance-attribute

kind: str

state instance-attribute

x class-attribute instance-attribute

x: float = 0.0

y class-attribute instance-attribute

y: float = 0.0

translation_x class-attribute instance-attribute

translation_x: float = 0.0

translation_y class-attribute instance-attribute

translation_y: float = 0.0

velocity_x class-attribute instance-attribute

velocity_x: float = 0.0

velocity_y class-attribute instance-attribute

velocity_y: float = 0.0

scale class-attribute instance-attribute

scale: float = 1.0

rotation class-attribute instance-attribute

rotation: float = 0.0

pointer_count class-attribute instance-attribute

pointer_count: int = 1

direction class-attribute instance-attribute

direction: Optional[str] = None

Tap dataclass

Tap(on_begin: Optional[GestureCallback] = None, on_change: Optional[GestureCallback] = None, on_end: Optional[GestureCallback] = None, kind: str = 'tap', on_tap: Optional[GestureCallback] = None, n_taps: int = 1, max_distance: float = 12.0)

Bases: _BaseGesture

Recognize n_taps quick taps.

Attributes:

Name Type Description
on_tap Optional[GestureCallback]

Called once the tap (or multi-tap) completes.

n_taps int

Number of consecutive taps required (2 for double-tap).

max_distance float

Maximum pointer travel (points) for a touch to still count as a tap.

on_tap class-attribute instance-attribute

on_tap: Optional[GestureCallback] = None

n_taps class-attribute instance-attribute

n_taps: int = 1

max_distance class-attribute instance-attribute

max_distance: float = 12.0

kind class-attribute instance-attribute

kind: str = 'tap'

LongPress dataclass

LongPress(on_begin: Optional[GestureCallback] = None, on_change: Optional[GestureCallback] = None, on_end: Optional[GestureCallback] = None, kind: str = 'long_press', on_long_press: Optional[GestureCallback] = None, min_duration_ms: float = 500.0, max_distance: float = 12.0)

Bases: _BaseGesture

Recognize a sustained press.

on_long_press fires as soon as the press has been held for min_duration_ms (matching UILongPressGestureRecognizer); on_end fires when the finger lifts.

Attributes:

Name Type Description
on_long_press Optional[GestureCallback]

Called at activation time.

min_duration_ms float

Hold duration required to activate.

max_distance float

Maximum pointer travel before the press fails.

on_long_press class-attribute instance-attribute

on_long_press: Optional[GestureCallback] = None

min_duration_ms class-attribute instance-attribute

min_duration_ms: float = 500.0

max_distance class-attribute instance-attribute

max_distance: float = 12.0

kind class-attribute instance-attribute

kind: str = 'long_press'

Pan dataclass

Pan(on_begin: Optional[GestureCallback] = None, on_change: Optional[GestureCallback] = None, on_end: Optional[GestureCallback] = None, kind: str = 'pan', min_distance: float = 10.0, min_pointers: int = 1)

Bases: _BaseGesture

Track a drag with translation and velocity.

Activates once the pointer travels min_distance points, then reports on_change for every movement with translation measured from the activation point, and on_end with release velocity.

Attributes:

Name Type Description
min_distance float

Travel (points) required before the pan activates.

min_pointers int

Minimum pointers that must be down.

min_distance class-attribute instance-attribute

min_distance: float = 10.0

min_pointers class-attribute instance-attribute

min_pointers: int = 1

kind class-attribute instance-attribute

kind: str = 'pan'

Swipe dataclass

Swipe(on_begin: Optional[GestureCallback] = None, on_change: Optional[GestureCallback] = None, on_end: Optional[GestureCallback] = None, kind: str = 'swipe', on_swipe: Optional[GestureCallback] = None, direction: SwipeDirection = 'any', min_velocity: float = 300.0)

Bases: _BaseGesture

Recognize a quick directional flick.

Attributes:

Name Type Description
on_swipe Optional[GestureCallback]

Called once on release with the resolved direction and release velocity.

direction SwipeDirection

Required direction, or "any".

min_velocity float

Minimum release speed in points/second.

on_swipe class-attribute instance-attribute

on_swipe: Optional[GestureCallback] = None

direction class-attribute instance-attribute

direction: SwipeDirection = 'any'

min_velocity class-attribute instance-attribute

min_velocity: float = 300.0

kind class-attribute instance-attribute

kind: str = 'swipe'

Pinch dataclass

Pinch(on_begin: Optional[GestureCallback] = None, on_change: Optional[GestureCallback] = None, on_end: Optional[GestureCallback] = None, kind: str = 'pinch')

Bases: _BaseGesture

Track a two-finger pinch; event.scale is relative to activation.

Attributes:

Name Type Description
kind str

kind class-attribute instance-attribute

kind: str = 'pinch'

Rotation dataclass

Rotation(on_begin: Optional[GestureCallback] = None, on_change: Optional[GestureCallback] = None, on_end: Optional[GestureCallback] = None, kind: str = 'rotation')

Bases: _BaseGesture

Track a two-finger rotation; event.rotation is in radians.

Attributes:

Name Type Description
kind str

kind class-attribute instance-attribute

kind: str = 'rotation'

GestureArbiter

GestureArbiter(specs: Sequence[Dict[str, Any]], emit: EmitFn)

Turn a raw pointer-event stream into gesture event payloads.

One arbiter serves one view. The host backend feeds it normalized pointer events (positions in the view's coordinate space, times in seconds, any monotonic clock) and provides an emit callback that forwards (gesture_index, payload) pairs to dispatch_event.

Long-press needs a timer: after each pointer event, hosts should check next_deadline and schedule a poll call for that time.

Methods:

Name Description
pointer_down

Record a pointer press and advance every recognizer.

pointer_move

Record pointer travel and advance every recognizer.

pointer_up

Record a pointer release and advance every recognizer.

cancel

Abort every in-flight gesture (e.g. touch stolen by a scroll parent).

poll

Advance time-based recognizers (long-press activation).

next_deadline

Earliest time poll should be called, or None.

has_active_pan

Whether a pan gesture is currently activated.

pointer_down

pointer_down(pointer_id: int, x: float, y: float, t: float) -> None

Record a pointer press and advance every recognizer.

pointer_move

pointer_move(pointer_id: int, x: float, y: float, t: float) -> None

Record pointer travel and advance every recognizer.

pointer_up

pointer_up(pointer_id: int, x: float, y: float, t: float) -> None

Record a pointer release and advance every recognizer.

cancel

cancel(t: float) -> None

Abort every in-flight gesture (e.g. touch stolen by a scroll parent).

poll

poll(t: float) -> None

Advance time-based recognizers (long-press activation).

next_deadline

next_deadline() -> Optional[float]

Earliest time poll should be called, or None.

has_active_pan

has_active_pan() -> bool

Whether a pan gesture is currently activated.

Android handlers use this to call requestDisallowInterceptTouchEvent so an enclosing ScrollView doesn't steal the drag.

event_from_payload

event_from_payload(payload: Dict[str, Any]) -> GestureEvent

Build a GestureEvent from a payload dict.

Unknown keys are dropped so platform handlers can attach extra diagnostics without breaking the public dataclass.

serialize_gestures

serialize_gestures(specs: Sequence[Any]) -> Tuple[List[Dict[str, Any]], Dict[str, Callable[..., Any]]]

Split gesture descriptors into native config dicts and event routers.

Parameters:

Name Type Description Default
specs Sequence[Any]

The value of an element's gestures prop. Plain dicts are passed through untouched (no callbacks to route).

required

Returns:

Type Description
List[Dict[str, Any]]

(clean_specs, events) where clean_specs is a list of

Dict[str, Callable[..., Any]]

JSON-ish config dicts (one per gesture, in order) and

Tuple[List[Dict[str, Any]], Dict[str, Callable[..., Any]]]

events maps "gesture:<i>" to a router that unpacks the

Tuple[List[Dict[str, Any]], Dict[str, Callable[..., Any]]]

native payload into a GestureEvent and invokes the right

Tuple[List[Dict[str, Any]], Dict[str, Callable[..., Any]]]

user callback.

make_arbiter

make_arbiter(specs: Sequence[Dict[str, Any]], emit: EmitFn) -> GestureArbiter

Build a GestureArbiter from serialized specs.

See also

  • The Gestures guide walks through taps, drags, and gesture-driven animations.
  • Animated pairs with Pan velocity for springs and decays.