Skip to content

Animated

PythonNative's Animated API mirrors React Native's. Build performant animations declaratively by binding AnimatedValue instances to the style of an Animated.View, Animated.Text, or Animated.Image. The reconciler holds a ref to the underlying native view. Connected values, derived expressions, and style bindings form a graph evaluated by the renderer, so supported animations bypass Python reconciliation on each frame. Unattached values, Python listeners, callable easing functions, and backends that decline native animation use the Python ticker.

Animated values, derived animated nodes, and native-driven animation.

Modeled on React Native's Animated API with an async-aware completion contract. The core primitives are:

  • AnimatedValue: a numeric cell attached to native view properties; animations drive it over time.
  • Derived nodes: every animated node supports interpolate (range mapping with numeric, color, and angle outputs) and Python arithmetic (opacity * 0.5, x + y, -value), producing read-only AnimatedNode instances that update whenever their inputs change.
  • Animated.timing / Animated.spring / Animated.decay: animation factories. The objects they return implement __await__, so you can write await Animated.timing(v, to=1.0) to suspend until the animation finishes.
  • Animated.sequence / Animated.parallel / Animated.stagger / Animated.delay / Animated.loop: composition; also awaitable.
  • Animated.event: build an event-prop callback that copies event fields into animated values (on_scroll=pn.Animated.event(y=v)).
  • Animated.diff_clamp: accumulate an input's deltas into a clamped range (the collapsing-header primitive).
  • Animated.View / Animated.Text / Animated.Image: components whose style may contain animated nodes, including inside transform entries.

Driver architecture (the native driver):

Mounted bindings install a serialized graph of connected values, arithmetic, interpolation, and view properties. When an animation starts, PythonNative offers its timing, spring, or decay specification to the renderer through ViewHandler.start_animation.

  • Accepted: the renderer evaluates the graph and applies its bindings without Python work on every frame. Completion callbacks settle the AnimatedValue and resolve awaiting tasks.
  • Declined (unattached values, callable easings, values feeding Python-side listeners, or an unsupported backend): a single background thread ticks the animation at ~60 Hz from Python, pushing each frame through set_animated_property. Semantics are identical; only the frame source differs.

On mobile, scroll and gesture bindings feed graph values before input is queued to Python. Derived expressions can run in the renderer alongside their source drivers. Backends without graph support use Python for derived bindings.

Example
import pythonnative as pn


@pn.component
def FadeIn():
    opacity = pn.use_animated_value(0.0)

    async def fade_in():
        await pn.Animated.timing(opacity, to=1.0, duration=400)
        await pn.Animated.timing(opacity, to=0.5, duration=200)

    pn.use_effect(fade_in, [])

    return pn.Animated.View(
        pn.Text("Hello!"),
        style={"opacity": opacity, "padding": 20},
    )

Classes:

Name Description
AnimatedNode

Base class for every animated node (settable leaves and derived nodes).

AnimatedValue

A numeric cell that can be attached to native view properties.

AnimatedInterpolation

Read-only node mapping a parent node through an input/output range.

AnimatedEvent

Callable event handler copying event fields into animated values.

Functions:

Name Description
native_animation_completed

Report a natively-driven animation as settled.

use_animated_value

Return an AnimatedValue that is stable across renders.

Attributes:

Name Type Description
Animated

Animated module-attribute

Animated = _AnimatedNamespace()

AnimatedNode

AnimatedNode()

Base class for every animated node (settable leaves and derived nodes).

An animated node holds a current output value and a set of (tag, prop) attachments binding it to native view properties. Whenever the node's output changes (a leaf was set or animated, or an input of a derived node changed), the new value is pushed to every attachment through the registry's set_animated_property and to every Python-side listener, then propagated to derived nodes built from this one.

Derived nodes are constructed with interpolate, with Python arithmetic operators (+, -, *, /, %, unary -), or with Animated.diff_clamp. They are read-only: only AnimatedValue leaves can be set or animated directly.

Methods:

Name Description
attach

Bind this node to prop of the native view under tag.

attachments

Snapshot of the current (tag, prop) bindings.

add_listener

Register callback for Python-driven changes to this node.

has_listeners

Whether any Python-side listeners are registered.

interpolate

Map this node's value through an input/output range.

Attributes:

Name Type Description
value Any

Return the node's current output value.

value property

value: Any

Return the node's current output value.

attach

attach(tag: int, prop: str) -> Callable[[], None]

Bind this node to prop of the native view under tag.

The current value is pushed immediately so the view reflects it even if no animation is running. Returns a detach callable.

attachments

attachments() -> List[Tuple[int, str]]

Snapshot of the current (tag, prop) bindings.

add_listener

add_listener(
    prop: str, callback: Callable[[Any], None]
) -> Callable[[], None]

Register callback for Python-driven changes to this node.

Returns an unsubscribe callable. prop is metadata only; it lets the subscriber differentiate this binding from others on the same node.

has_listeners

has_listeners() -> bool

Whether any Python-side listeners are registered.

interpolate

interpolate(
    input_range: Sequence[float],
    output_range: Sequence[Any],
    extrapolate: str = "extend",
    extrapolate_left: Optional[str] = None,
    extrapolate_right: Optional[str] = None,
) -> "AnimatedInterpolation"

Map this node's value through an input/output range.

Mirrors React Native's interpolate. output_range may contain numbers, colors ("#RRGGBB" / "#AARRGGBB"), or angle strings ("45deg" / "0.5rad", emitted as numeric degrees for the rotate transform).

Parameters:

Name Type Description Default
input_range Sequence[float]

Monotonically non-decreasing breakpoints for this node's value. At least two entries.

required
output_range Sequence[Any]

Output breakpoints, same length as input_range.

required
extrapolate str

Behavior outside the input range: "extend" (continue the edge segment's slope, default), "clamp" (pin to the edge output), or "identity" (return the input unchanged).

'extend'
extrapolate_left Optional[str]

Override extrapolate below the range.

None
extrapolate_right Optional[str]

Override extrapolate above the range.

None

Returns:

Type Description
'AnimatedInterpolation'

A derived, read-only animated node.

Example
header_height = scroll_y.interpolate(
    input_range=[0, 120],
    output_range=[160, 56],
    extrapolate="clamp",
)

AnimatedValue

AnimatedValue(initial: float = 0.0)

Bases: AnimatedNode

A numeric cell that can be attached to native view properties.

Animated components (Animated.View et al.) attach the value to (tag, prop) bindings after mount. Setting the value pushes the new number to every attached native view through the registry's set_animated_property (and through every derived node built from this value), and when an animation can be driven natively, the platform animates those same bindings directly.

Python-side listeners registered via add_listener observe every Python-driven change. Natively-driven animations intentionally skip per-frame Python callbacks (that's the point); listeners see the final settled value.

Methods:

Name Description
set_value

Set the value immediately, pushing to native views and listeners.

stop_animation

Cancel any in-flight animation on this value (native or Python).

Attributes:

Name Type Description
value float

Return the current numeric value (without subscribing).

value property

value: float

Return the current numeric value (without subscribing).

set_value

set_value(new_value: float) -> None

Set the value immediately, pushing to native views and listeners.

stop_animation

stop_animation() -> None

Cancel any in-flight animation on this value (native or Python).

AnimatedInterpolation

AnimatedInterpolation(
    parent: AnimatedNode,
    input_range: Sequence[float],
    output_range: Sequence[Any],
    extrapolate: str = "extend",
    extrapolate_left: Optional[str] = None,
    extrapolate_right: Optional[str] = None,
)

Bases: AnimatedNode

Read-only node mapping a parent node through an input/output range.

Built via AnimatedNode.interpolate; see that method for the semantics of the arguments.

Attributes:

Name Type Description
value Any

Return the interpolated output for the parent's current value.

value property

value: Any

Return the interpolated output for the parent's current value.

AnimatedEvent

AnimatedEvent(
    listener: Optional[Callable[..., None]] = None,
    **bindings: AnimatedValue
)

Callable event handler copying event fields into animated values.

Built via pn.Animated.event(...). Each keyword argument names a field on the incoming event payload (a dict key for scroll payloads such as {"x": ..., "y": ...}, or an attribute for GestureEvent instances) and maps it onto an AnimatedValue.

Because the result is an ordinary callable, it can be passed to any event prop:

scroll_y = pn.use_animated_value(0.0)
pn.ScrollView(..., on_scroll=pn.Animated.event(y=scroll_y))

tx = pn.use_animated_value(0.0)
gestures.Pan(on_change=pn.Animated.event(translation_x=tx))

native_animation_completed

native_animation_completed(
    anim_id: int, finished: bool = True
) -> None

Report a natively-driven animation as settled.

Called by platform handlers from their completion callbacks (iOS UIView completion blocks, Android withEndAction / DynamicAnimation.OnAnimationEndListener). Safe to call from any thread; unknown ids are ignored (e.g. an animation cancelled moments before its completion fired).

Parameters:

Name Type Description Default
anim_id int

The id passed to ViewHandler.start_animation.

required
finished bool

False when the platform reports the animation was interrupted rather than running to completion.

True

use_animated_value

use_animated_value(initial: float = 0.0) -> AnimatedValue

Return an AnimatedValue that is stable across renders.

Convenience wrapper for the common pattern pn.use_memo(lambda: AnimatedValue(initial), []). The same instance is returned on every render of the same component, so you can drive it from event handlers without recreating it.

Parameters:

Name Type Description Default
initial float

The starting numeric value.

0.0

Returns:

Type Description
AnimatedValue

A mount-stable AnimatedValue.

Example
import pythonnative as pn


@pn.component
def FadeIn():
    opacity = pn.use_animated_value(0.0)

    async def fade_in():
        await pn.Animated.timing(opacity, to=1.0, duration=300)

    pn.use_effect(fade_in, [])
    return pn.Animated.View(
        pn.Text("Hello"),
        style=pn.style(opacity=opacity),
    )

See also

  • The Animations guide walks through fade-ins, springs, sequences, and gesture-driven animations.
  • use_ref explains the ref semantics that back Animated.View.