| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 7a5923c commit 8103710
33 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -26,17 +26,18 @@ | |||
| 26 | 26 | ||
| 27 | 27 | ## Overview | |
| 28 | 28 | ||
| 29 | - PythonNative is a cross-platform toolkit for building native Android and iOS apps in Python. It provides a **declarative, React-like component model** with automatic reconciliation, powered by Chaquopy on Android and rubicon-objc on iOS. Describe your UI as a tree of elements, manage state with `set_state()`, and let PythonNative handle creating and updating native views. | ||
| 29 | + PythonNative is a cross-platform toolkit for building native Android and iOS apps in Python. It provides a **declarative, React-like component model** with hooks and automatic reconciliation, powered by Chaquopy on Android and rubicon-objc on iOS. Write function components with `use_state`, `use_effect`, and friends, just like React, and let PythonNative handle creating and updating native views. | ||
| 30 | 30 | ||
| 31 | 31 | ## Features | |
| 32 | 32 | ||
| 33 | 33 | - **Declarative UI:** Describe *what* your UI should look like with element functions (`Text`, `Button`, `Column`, `Row`, etc.). PythonNative creates and updates native views automatically. | |
| 34 | - - **Reactive state:** Call `self.set_state(key=value)` and the framework re-renders only what changed — no manual view mutation. | ||
| 34 | + - **Hooks and function components:** Manage state with `use_state`, side effects with `use_effect`, and navigation with `use_navigation`, all through one consistent pattern. | ||
| 35 | + - **`style` prop:** Pass all visual and layout properties through a single `style` dict, composable via `StyleSheet`. | ||
| 35 | 36 | - **Virtual view tree + reconciler:** Element trees are diffed and patched with minimal native mutations, similar to React's reconciliation. | |
| 36 | 37 | - **Direct native bindings:** Python calls platform APIs directly through Chaquopy and rubicon-objc, with no JavaScript bridge. | |
| 37 | 38 | - **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app. | |
| 38 | - - **Navigation:** Push and pop screens with argument passing for multi-page apps. | ||
| 39 | - - **Bundled templates:** Android Gradle and iOS Xcode templates are included — scaffolding requires no network access. | ||
| 39 | + - **Navigation:** Push and pop screens with argument passing via the `use_navigation()` hook. | ||
| 40 | + - **Bundled templates:** Android Gradle and iOS Xcode templates are included, so scaffolding requires no network access. | ||
| 40 | 41 | ||
| 41 | 42 | ## Quick Start | |
| 42 | 43 | ||
@@ -52,21 +53,17 @@ pip install pythonnative | |||
| 52 | 53 | import pythonnative as pn | |
| 53 | 54 | ||
| 54 | 55 | ||
| 55 | - class MainPage(pn.Page): | ||
| 56 | - def __init__(self, native_instance): | ||
| 57 | - super().__init__(native_instance) | ||
| 58 | - self.state = {"count": 0} | ||
| 59 | - | ||
| 60 | - def render(self): | ||
| 61 | - return pn.Column( | ||
| 62 | - pn.Text(f"Count: {self.state['count']}", font_size=24), | ||
| 63 | - pn.Button( | ||
| 64 | - "Tap me", | ||
| 65 | - on_click=lambda: self.set_state(count=self.state["count"] + 1), | ||
| 66 | - ), | ||
| 67 | - spacing=12, | ||
| 68 | - padding=16, | ||
| 69 | - ) | ||
| 56 | + @pn.component | ||
| 57 | + def MainPage(): | ||
| 58 | + count, set_count = pn.use_state(0) | ||
| 59 | + return pn.Column( | ||
| 60 | + pn.Text(f"Count: {count}", style={"font_size": 24}), | ||
| 61 | + pn.Button( | ||
| 62 | + "Tap me", | ||
| 63 | + on_click=lambda: set_count(count + 1), | ||
| 64 | + ), | ||
| 65 | + style={"spacing": 12, "padding": 16}, | ||
| 66 | + ) | ||
| 70 | 67 | ``` | |
| 71 | 68 | ||
| 72 | 69 | ## Documentation | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,10 +1,10 @@ | |||
| 1 | 1 | # Component Property Reference | |
| 2 | 2 | ||
| 3 | - All style and behaviour properties are passed as keyword arguments to element functions. | ||
| 3 | + All visual and layout properties are passed via the `style` dict (or list of dicts) to element functions. Behavioural properties (callbacks, data, content) remain as keyword arguments. | ||
| 4 | 4 | ||
| 5 | - ## Common layout properties | ||
| 5 | + ## Common layout properties (inside `style`) | ||
| 6 | 6 | ||
| 7 | - All components accept these layout properties: | ||
| 7 | + All components accept these layout properties in their `style` dict: | ||
| 8 | 8 | ||
| 9 | 9 | - `width` — fixed width in dp (Android) / pt (iOS) | |
| 10 | 10 | - `height` — fixed height | |
@@ -13,108 +13,104 @@ All components accept these layout properties: | |||
| 13 | 13 | - `min_width`, `max_width` — width constraints | |
| 14 | 14 | - `min_height`, `max_height` — height constraints | |
| 15 | 15 | - `align_self` — override parent alignment (`"fill"`, `"center"`, etc.) | |
| 16 | - - `key` — stable identity for reconciliation | ||
| 16 | + - `key` — stable identity for reconciliation (passed as a kwarg, not inside `style`) | ||
| 17 | 17 | ||
| 18 | 18 | ## Text | |
| 19 | 19 | ||
| 20 | 20 | ```python | |
| 21 | - pn.Text(text, font_size=None, color=None, bold=False, text_align=None, | ||
| 22 | - background_color=None, max_lines=None) | ||
| 21 | + pn.Text(text, style={"font_size": 18, "color": "#333", "bold": True, "text_align": "center"}) | ||
| 23 | 22 | ``` | |
| 24 | 23 | ||
| 25 | - - `text` — display string | ||
| 26 | - - `font_size` — size in sp (Android) / pt (iOS) | ||
| 27 | - - `color` — text colour (`#RRGGBB` or `#AARRGGBB`) | ||
| 28 | - - `bold` — bold weight | ||
| 29 | - - `text_align` — `"left"`, `"center"`, or `"right"` | ||
| 30 | - - `background_color` — view background | ||
| 31 | - - `max_lines` — limit visible lines | ||
| 24 | + - `text` — display string (positional) | ||
| 25 | + - Style properties: `font_size`, `color`, `bold`, `text_align`, `background_color`, `max_lines` | ||
| 32 | 26 | ||
| 33 | 27 | ## Button | |
| 34 | 28 | ||
| 35 | 29 | ```python | |
| 36 | - pn.Button(title, on_click=None, color=None, background_color=None, | ||
| 37 | - font_size=None, enabled=True) | ||
| 30 | + pn.Button(title, on_click=handler, style={"color": "#FFF", "background_color": "#007AFF", "font_size": 16}) | ||
| 38 | 31 | ``` | |
| 39 | 32 | ||
| 40 | - - `title` — button label | ||
| 33 | + - `title` — button label (positional) | ||
| 41 | 34 | - `on_click` — callback `() -> None` | |
| 42 | - - `color` — title text colour | ||
| 43 | - - `background_color` — button background | ||
| 44 | - - `enabled` — interactive state | ||
| 35 | + - `enabled` — interactive state (kwarg, default `True`) | ||
| 36 | + - Style properties: `color`, `background_color`, `font_size` | ||
| 45 | 37 | ||
| 46 | 38 | ## Column / Row | |
| 47 | 39 | ||
| 48 | 40 | ```python | |
| 49 | - pn.Column(*children, spacing=0, padding=None, alignment=None, background_color=None) | ||
| 50 | - pn.Row(*children, spacing=0, padding=None, alignment=None, background_color=None) | ||
| 41 | + pn.Column(*children, style={"spacing": 12, "padding": 16, "align_items": "center"}) | ||
| 42 | + pn.Row(*children, style={"spacing": 8, "justify_content": "space_between"}) | ||
| 51 | 43 | ``` | |
| 52 | 44 | ||
| 53 | - - `spacing` — gap between children (dp / pt) | ||
| 54 | - - `padding` — inner padding (int for all sides, or dict with `horizontal`, `vertical`, `left`, `top`, `right`, `bottom`) | ||
| 55 | - - `alignment` — cross-axis: `"fill"`, `"center"`, `"leading"`, `"trailing"`, `"start"`, `"end"`, `"top"`, `"bottom"` | ||
| 56 | - - `background_color` — container background | ||
| 45 | + - `*children` — child elements (positional) | ||
| 46 | + - Style properties: | ||
| 47 | + - `spacing` — gap between children (dp / pt) | ||
| 48 | + - `padding` — inner padding (int for all sides, or dict with `horizontal`, `vertical`, `left`, `top`, `right`, `bottom`) | ||
| 49 | + - `alignment` — cross-axis alignment shorthand | ||
| 50 | + - `align_items` — cross-axis alignment: `"fill"`, `"center"`, `"leading"` / `"start"`, `"trailing"` / `"end"`, `"stretch"` | ||
| 51 | + - `justify_content` — main-axis distribution: `"start"`, `"center"`, `"end"`, `"space_between"`, `"space_around"` | ||
| 52 | + - `background_color` — container background | ||
| 57 | 53 | ||
| 58 | 54 | ## View | |
| 59 | 55 | ||
| 60 | 56 | ```python | |
| 61 | - pn.View(*children, background_color=None, padding=None) | ||
| 57 | + pn.View(*children, style={"background_color": "#F5F5F5", "padding": 16}) | ||
| 62 | 58 | ``` | |
| 63 | 59 | ||
| 64 | - Generic container (UIView / FrameLayout). Supports all layout properties. | ||
| 60 | + Generic container (UIView / FrameLayout). Supports all layout properties in `style`. | ||
| 65 | 61 | ||
| 66 | 62 | ## SafeAreaView | |
| 67 | 63 | ||
| 68 | 64 | ```python | |
| 69 | - pn.SafeAreaView(*children, background_color=None, padding=None) | ||
| 65 | + pn.SafeAreaView(*children, style={"background_color": "#FFF", "padding": 8}) | ||
| 70 | 66 | ``` | |
| 71 | 67 | ||
| 72 | 68 | Container that respects safe area insets (notch, status bar). | |
| 73 | 69 | ||
| 74 | 70 | ## ScrollView | |
| 75 | 71 | ||
| 76 | 72 | ```python | |
| 77 | - pn.ScrollView(child, background_color=None) | ||
| 73 | + pn.ScrollView(child, style={"background_color": "#FFF"}) | ||
| 78 | 74 | ``` | |
| 79 | 75 | ||
| 80 | 76 | ## TextInput | |
| 81 | 77 | ||
| 82 | 78 | ```python | |
| 83 | - pn.TextInput(value="", placeholder="", on_change=None, secure=False, | ||
| 84 | - font_size=None, color=None, background_color=None) | ||
| 79 | + pn.TextInput(value="", placeholder="Enter text", on_change=handler, secure=False, | ||
| 80 | + style={"font_size": 16, "color": "#000", "background_color": "#FFF"}) | ||
| 85 | 81 | ``` | |
| 86 | 82 | ||
| 87 | 83 | - `on_change` — callback `(str) -> None` receiving new text | |
| 88 | 84 | ||
| 89 | 85 | ## Image | |
| 90 | 86 | ||
| 91 | 87 | ```python | |
| 92 | - pn.Image(source="", width=None, height=None, scale_type=None, background_color=None) | ||
| 88 | + pn.Image(source="https://example.com/photo.jpg", style={"width": 200, "height": 150, "scale_type": "cover"}) | ||
| 93 | 89 | ``` | |
| 94 | 90 | ||
| 95 | 91 | - `source` — image URL (`http://...` / `https://...`) or local resource name | |
| 96 | - - `scale_type` — `"cover"`, `"contain"`, `"stretch"`, `"center"` | ||
| 92 | + - Style properties: `width`, `height`, `scale_type` (`"cover"`, `"contain"`, `"stretch"`, `"center"`), `background_color` | ||
| 97 | 93 | ||
| 98 | 94 | ## Switch | |
| 99 | 95 | ||
| 100 | 96 | ```python | |
| 101 | - pn.Switch(value=False, on_change=None) | ||
| 97 | + pn.Switch(value=False, on_change=handler) | ||
| 102 | 98 | ``` | |
| 103 | 99 | ||
| 104 | 100 | - `on_change` — callback `(bool) -> None` | |
| 105 | 101 | ||
| 106 | 102 | ## Slider | |
| 107 | 103 | ||
| 108 | 104 | ```python | |
| 109 | - pn.Slider(value=0.0, min_value=0.0, max_value=1.0, on_change=None) | ||
| 105 | + pn.Slider(value=0.5, min_value=0.0, max_value=1.0, on_change=handler) | ||
| 110 | 106 | ``` | |
| 111 | 107 | ||
| 112 | 108 | - `on_change` — callback `(float) -> None` | |
| 113 | 109 | ||
| 114 | 110 | ## ProgressBar | |
| 115 | 111 | ||
| 116 | 112 | ```python | |
| 117 | - pn.ProgressBar(value=0.0, background_color=None) | ||
| 113 | + pn.ProgressBar(value=0.5, style={"background_color": "#EEE"}) | ||
| 118 | 114 | ``` | |
| 119 | 115 | ||
| 120 | 116 | - `value` — 0.0 to 1.0 | |
@@ -128,13 +124,13 @@ pn.ActivityIndicator(animating=True) | |||
| 128 | 124 | ## WebView | |
| 129 | 125 | ||
| 130 | 126 | ```python | |
| 131 | - pn.WebView(url="") | ||
| 127 | + pn.WebView(url="https://example.com") | ||
| 132 | 128 | ``` | |
| 133 | 129 | ||
| 134 | 130 | ## Spacer | |
| 135 | 131 | ||
| 136 | 132 | ```python | |
| 137 | - pn.Spacer(size=None, flex=None) | ||
| 133 | + pn.Spacer(size=16, flex=1) | ||
| 138 | 134 | ``` | |
| 139 | 135 | ||
| 140 | 136 | - `size` — fixed dimension in dp / pt | |
@@ -143,24 +139,25 @@ pn.Spacer(size=None, flex=None) | |||
| 143 | 139 | ## Pressable | |
| 144 | 140 | ||
| 145 | 141 | ```python | |
| 146 | - pn.Pressable(child, on_press=None, on_long_press=None) | ||
| 142 | + pn.Pressable(child, on_press=handler, on_long_press=handler) | ||
| 147 | 143 | ``` | |
| 148 | 144 | ||
| 149 | 145 | Wraps any child element with tap/long-press handling. | |
| 150 | 146 | ||
| 151 | 147 | ## Modal | |
| 152 | 148 | ||
| 153 | 149 | ```python | |
| 154 | - pn.Modal(*children, visible=False, on_dismiss=None, title=None, background_color=None) | ||
| 150 | + pn.Modal(*children, visible=show_modal, on_dismiss=handler, title="Confirm", | ||
| 151 | + style={"background_color": "#FFF"}) | ||
| 155 | 152 | ``` | |
| 156 | 153 | ||
| 157 | 154 | Overlay dialog shown when `visible=True`. | |
| 158 | 155 | ||
| 159 | 156 | ## FlatList | |
| 160 | 157 | ||
| 161 | 158 | ```python | |
| 162 | - pn.FlatList(data=None, render_item=None, key_extractor=None, | ||
| 163 | - separator_height=0, background_color=None) | ||
| 159 | + pn.FlatList(data=items, render_item=render_fn, key_extractor=key_fn, | ||
| 160 | + separator_height=1, style={"background_color": "#FFF"}) | ||
| 164 | 161 | ``` | |
| 165 | 162 | ||
| 166 | 163 | - `data` — list of items | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,16 +2,16 @@ | |||
| 2 | 2 | ||
| 3 | 3 | ## Public API | |
| 4 | 4 | ||
| 5 | - ### Page | ||
| 5 | + ### create_page | ||
| 6 | 6 | ||
| 7 | - `pythonnative.Page` — base class for screens. Subclass it, implement `render()`, and use `set_state()` to trigger re-renders. | ||
| 7 | + `pythonnative.create_page(...)` — called internally by native templates to bootstrap the root component. You don't call this directly. | ||
| 8 | 8 | ||
| 9 | 9 | ### Element functions | |
| 10 | 10 | ||
| 11 | 11 | - `pythonnative.Text`, `Button`, `Column`, `Row`, `ScrollView`, `TextInput`, `Image`, `Switch`, `ProgressBar`, `ActivityIndicator`, `WebView`, `Spacer` | |
| 12 | 12 | - `pythonnative.View`, `SafeAreaView`, `Modal`, `Slider`, `Pressable`, `FlatList` | |
| 13 | 13 | ||
| 14 | - Each returns an `Element` descriptor. See the Component Property Reference for full signatures. | ||
| 14 | + Each returns an `Element` descriptor. Visual and layout properties are passed via `style={...}`. See the Component Property Reference for full details. | ||
| 15 | 15 | ||
| 16 | 16 | ### Element | |
| 17 | 17 | ||
@@ -24,6 +24,7 @@ Function component primitives: | |||
| 24 | 24 | - `pythonnative.component` — decorator to create a function component | |
| 25 | 25 | - `pythonnative.use_state(initial)` — local component state | |
| 26 | 26 | - `pythonnative.use_effect(effect, deps)` — side effects | |
| 27 | + - `pythonnative.use_navigation()` — navigation handle (push/pop/get_args) | ||
| 27 | 28 | - `pythonnative.use_memo(factory, deps)` — memoised values | |
| 28 | 29 | - `pythonnative.use_callback(fn, deps)` — stable function references | |
| 29 | 30 | - `pythonnative.use_ref(initial)` — mutable ref object | |
@@ -47,12 +48,12 @@ Function component primitives: | |||
| 47 | 48 | ||
| 48 | 49 | - `pythonnative.utils.IS_ANDROID` — platform flag with robust detection for Chaquopy/Android. | |
| 49 | 50 | - `pythonnative.utils.get_android_context()` — returns the current Android `Activity`/`Context` when running on Android. | |
| 50 | - - `pythonnative.utils.set_android_context(ctx)` — set by `Page` on Android; you generally don't call this directly. | ||
| 51 | + - `pythonnative.utils.set_android_context(ctx)` — set internally during page bootstrapping; you generally don't call this directly. | ||
| 51 | 52 | - `pythonnative.utils.get_android_fragment_container()` — returns the current Fragment container `ViewGroup` used for page rendering. | |
| 52 | 53 | ||
| 53 | 54 | ## Reconciler | |
| 54 | 55 | ||
| 55 | - `pythonnative.reconciler.Reconciler` — diffs element trees and applies minimal native mutations. Supports key-based child reconciliation, function components, and context providers. Used internally by `Page`. | ||
| 56 | + `pythonnative.reconciler.Reconciler` — diffs element trees and applies minimal native mutations. Supports key-based child reconciliation, function components, and context providers. Used internally by `create_page`. | ||
| 56 | 57 | ||
| 57 | 58 | ## Hot reload | |
| 58 | 59 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments