Skip to content

Native views

The bridge between PythonNative's element tree and concrete native widgets. Every element type maps to a ViewHandler implementation in the NativeViewRegistry; the platform-specific handlers are registered lazily so importing pythonnative on the desktop never pulls in Chaquopy or rubicon-objc.

Platform-specific native-view creation and update logic.

This package provides the NativeViewRegistry that maps element type names (e.g., "Text", "Button") to platform-specific ViewHandler implementations. The reconciler calls the registry to create, update, and re-parent native views.

Platform handlers live in dedicated submodules:

  • pythonnative.native_views.base: shared ViewHandler protocol and utilities.
  • pythonnative.native_views.android: Android handlers (Chaquopy / Java bridge).
  • pythonnative.native_views.ios: iOS handlers (rubicon-objc).

All platform-branching is handled at registration time via lazy imports, so this package can be imported on any platform for testing. A mock registry can be installed via set_registry to drive the reconciler with no real native views.

Modules:

Name Description
android

Android native-view handlers (Chaquopy / Java bridge).

base

Shared base classes and utilities for native-view handlers.

desktop

Desktop native-view handlers (Tkinter).

ios

iOS native-view handlers (rubicon-objc).

Classes:

Name Description
NativeViewRegistry

Map element type names to platform-specific view handlers.

Functions:

Name Description
get_registry

Return the process-wide registry, lazily registering handlers.

refresh_registry

Re-run SDK handler installation against the existing registry.

set_registry

Install a custom registry (primarily for testing).

NativeViewRegistry

NativeViewRegistry()

Map element type names to platform-specific view handlers.

The reconciler depends only on this protocol: create_view, update_view, add_child, remove_child, insert_child, set_frame, measure_intrinsic. Implementations may be real (Android/iOS) or mocked for tests.

Methods:

Name Description
register

Register handler to service elements of type type_name.

create_view

Create a native view for type_name and apply initial props.

update_view

Apply changed_props to an existing native view.

add_child

Append child to parent.

remove_child

Remove child from parent.

insert_child

Insert child into parent at index.

set_frame

Position and size a native view via the appropriate handler.

measure_intrinsic

Return the natural (width, height) of a content-sized view.

register

register(type_name: str, handler: ViewHandler) -> None

Register handler to service elements of type type_name.

Parameters:

Name Type Description Default
type_name str

The element type name (e.g., "Text").

required
handler ViewHandler

A ViewHandler instance for the active platform.

required

create_view

create_view(type_name: str, props: Dict[str, Any]) -> Any

Create a native view for type_name and apply initial props.

Parameters:

Name Type Description Default
type_name str

The element type name.

required
props Dict[str, Any]

Initial props dict.

required

Returns:

Type Description
Any

The platform-native view object.

Raises:

Type Description
ValueError

If no handler is registered for type_name.

update_view

update_view(native_view: Any, type_name: str, changed_props: Dict[str, Any]) -> None

Apply changed_props to an existing native view.

Silently ignored if no handler is registered for type_name.

Parameters:

Name Type Description Default
native_view Any

The platform-native view.

required
type_name str

The element type name.

required
changed_props Dict[str, Any]

A dict containing only props whose values changed since the previous render. Removed props are signaled with a value of None.

required

add_child

add_child(parent: Any, child: Any, parent_type: str) -> None

Append child to parent.

Parameters:

Name Type Description Default
parent Any

Parent native view.

required
child Any

Native view to append.

required
parent_type str

Element type of the parent (for handler lookup).

required

remove_child

remove_child(parent: Any, child: Any, parent_type: str) -> None

Remove child from parent.

Parameters:

Name Type Description Default
parent Any

Parent native view.

required
child Any

Child native view to remove.

required
parent_type str

Element type of the parent.

required

insert_child

insert_child(parent: Any, child: Any, parent_type: str, index: int) -> None

Insert child into parent at index.

Parameters:

Name Type Description Default
parent Any

Parent native view.

required
child Any

Child native view to insert.

required
parent_type str

Element type of the parent.

required
index int

Zero-based insertion position among parent's existing children.

required

set_frame

set_frame(native_view: Any, type_name: str, x: float, y: float, width: float, height: float) -> None

Position and size a native view via the appropriate handler.

Called by the reconciler's layout pass after every commit, with coordinates computed by pythonnative.layout in points relative to the parent's content origin.

measure_intrinsic

measure_intrinsic(native_view: Any, type_name: str, max_width: float, max_height: float) -> Tuple[float, float]

Return the natural (width, height) of a content-sized view.

Used by the layout engine for leaves whose intrinsic size depends on their content (text, buttons, images).

get_registry

get_registry() -> NativeViewRegistry

Return the process-wide registry, lazily registering handlers.

The first call instantiates the registry, registers either the Android or iOS handlers based on IS_ANDROID, then layers on every decorator-registered SDK handler (and any handlers exposed by third-party packages via the pythonnative.handlers entry point group). Subsequent calls return the same instance.

Returns:

Type Description
NativeViewRegistry

The active NativeViewRegistry.

refresh_registry

refresh_registry() -> NativeViewRegistry

Re-run SDK handler installation against the existing registry.

Call this after registering a new component at runtime if the registry has already been instantiated. This is mostly useful in REPL sessions and tests; the normal flow is "register, then call get_registry" and the handlers come along automatically.

Returns:

Type Description
NativeViewRegistry

The active NativeViewRegistry.

set_registry

set_registry(registry: Optional[NativeViewRegistry]) -> None

Install a custom registry (primarily for testing).

Replaces the lazy singleton so subsequent get_registry calls return registry. Pass a mock to drive the reconciler from unit tests without touching real native APIs. Pass None to reset the singleton; the next get_registry call will then rebuild it from scratch.

Parameters:

Name Type Description Default
registry Optional[NativeViewRegistry]

The replacement registry, or None to clear.

required

Base classes

Shared base classes and utilities for native-view handlers.

Provides the ViewHandler protocol implemented by Android and iOS handlers, plus the parse_color_int helper shared across platforms.

Layout itself is not a handler responsibility. The pure-Python flex engine in pythonnative.layout owns sizing and positioning; handlers receive computed frames via set_frame and optionally expose an intrinsic-size hook via measure_intrinsic for content-sized leaves (text, buttons, images).

Classes:

Name Description
ViewHandler

Protocol implemented by every native-view handler.

Functions:

Name Description
parse_color_int

Parse a color value into a signed 32-bit ARGB int.

ViewHandler

Protocol implemented by every native-view handler.

A ViewHandler knows how to create, update, and re-parent native views of one element type. The reconciler dispatches through the NativeViewRegistry; handlers never need to know about Element or VNode.

Subclasses must override create and update. Container handlers override the child-management methods; leaf handlers can leave them as no-ops. Handlers whose intrinsic size depends on content (text, buttons, images) override measure_intrinsic.

Methods:

Name Description
create

Create a fresh native view and apply initial visual props.

update

Apply only the visual props that changed since the last render.

add_child

Append child to parent. No-op for leaf handlers.

remove_child

Remove child from parent. No-op for leaf handlers.

insert_child

Insert child at index. Defaults to appending.

set_frame

Position and size native_view relative to its parent.

measure_intrinsic

Return the natural (width, height) of a content-sized view.

create

create(props: Dict[str, Any]) -> Any

Create a fresh native view and apply initial visual props.

Layout-related props (width, height, flex, padding, etc.) are consumed by the layout engine and applied via set_frame, so handlers should ignore them here.

Parameters:

Name Type Description Default
props Dict[str, Any]

Initial props dict.

required

Returns:

Type Description
Any

The platform-native view object.

Raises:

Type Description
NotImplementedError

Subclasses must override.

update

update(native_view: Any, changed_props: Dict[str, Any]) -> None

Apply only the visual props that changed since the last render.

Parameters:

Name Type Description Default
native_view Any

The platform-native view to mutate.

required
changed_props Dict[str, Any]

Props whose values changed (a value of None indicates the prop was removed).

required

Raises:

Type Description
NotImplementedError

Subclasses must override.

add_child

add_child(parent: Any, child: Any) -> None

Append child to parent. No-op for leaf handlers.

remove_child

remove_child(parent: Any, child: Any) -> None

Remove child from parent. No-op for leaf handlers.

insert_child

insert_child(parent: Any, child: Any, index: int) -> None

Insert child at index. Defaults to appending.

set_frame

set_frame(native_view: Any, x: float, y: float, width: float, height: float) -> None

Position and size native_view relative to its parent.

Coordinates are in points and relative to the parent's content origin. Default no-op so handlers that don't need explicit positioning (e.g., Modal) can opt out.

Parameters:

Name Type Description Default
native_view Any

The platform-native view.

required
x float

X-coordinate (points) of the view's top-left corner relative to its parent's content origin.

required
y float

Y-coordinate (points) of the view's top-left corner.

required
width float

View width in points.

required
height float

View height in points.

required

measure_intrinsic

measure_intrinsic(native_view: Any, max_width: float, max_height: float) -> Tuple[float, float]

Return the natural (width, height) of a content-sized view.

Used by the layout engine for leaves whose size depends on their content (text, buttons, images). Either max_width or max_height may be math.inf to indicate no constraint.

The default implementation returns (0, 0); override for leaves whose size depends on their content. Container handlers leave this alone — the engine sizes containers by laying out their children.

Parameters:

Name Type Description Default
native_view Any

The platform-native view to measure.

required
max_width float

Maximum width in points (or math.inf).

required
max_height float

Maximum height in points (or math.inf).

required

Returns:

Type Description
Tuple[float, float]

(width, height) in points.

parse_color_int

parse_color_int(color: Union[str, int]) -> int

Parse a color value into a signed 32-bit ARGB int.

Accepts "#RRGGBB", "#AARRGGBB", or a raw integer. Java APIs such as setBackgroundColor expect a signed 32-bit int, so values with a high alpha byte (e.g., 0xFF......) must be converted to their negative two's-complement equivalent.

Parameters:

Name Type Description Default
color Union[str, int]

Hex string (with or without leading #) or an int.

required

Returns:

Type Description
int

Signed 32-bit ARGB int suitable for Android's color APIs.

Platform handlers

The Android and iOS handler implementations live in pythonnative.native_views.android and pythonnative.native_views.ios respectively. They are imported only at runtime on the corresponding platform; we don't render their API tables here because they're internal to the runtime and require platform-only dependencies (Chaquopy / rubicon-objc) to be importable for mkdocstrings to introspect them.

Next steps