Navigation¶
This guide shows how to navigate between pages and handle lifecycle events.
Push / Pop¶
Use push and pop on your Page to change screens. You can pass a dotted path string or a class reference.
import pythonnative as pn
class MainPage(pn.Page):
def on_create(self):
stack = pn.StackView()
btn = pn.Button("Go next")
btn.set_on_click(lambda: self.push("app.second_page.SecondPage", args={"message": "Hello"}))
stack.add_view(btn)
self.set_root_view(stack)
On the target page:
class SecondPage(pn.Page):
def on_create(self):
args = self.get_args()
message = args.get("message", "Second")
stack = pn.StackView()
stack.add_view(pn.Label(message))
back = pn.Button("Back")
back.set_on_click(lambda: self.pop())
stack.add_view(back)
self.set_root_view(stack)
Lifecycle¶
PythonNative forwards lifecycle events from the host:
on_createon_starton_resumeon_pauseon_stopon_destroyon_restart(Android only)on_save_instance_stateon_restore_instance_state
Android uses a single MainActivity hosting a NavHostFragment and a generic PageFragment per page. iOS forwards viewWillAppear/viewWillDisappear via an internal registry.
Notes¶
- On Android,
pushnavigates viaNavControllerto aPageFragmentand passespage_pathand optional JSONargs. - On iOS,
pushuses the rootUINavigationControllerto push a newViewControllerand passes page info via KVC.
Platform specifics¶
iOS (UIViewController per page)¶
- Each PythonNative page is hosted by a Swift
ViewControllerinstance. - Pages are pushed and popped on a root
UINavigationController. - Lifecycle is forwarded from Swift to the registered Python page instance.
- Root view wiring:
Page.set_root_viewsizes and inserts the Python-native view into the controller’s view.
Why this matches iOS conventions
- iOS apps commonly model screens as UIViewControllers and use UINavigationController for hierarchical navigation.
- The approach integrates cleanly with add-to-app and system behaviors (e.g., state restoration).
Android (single Activity, Fragment stack)¶
- Single host
MainActivitysets aNavHostFragmentcontaining a navigation graph. - Each PythonNative page is represented by a generic
PageFragmentwhich instantiates the Python page and attaches its root view. push/popdelegate toNavController(via a smallNavigatorhelper).- Arguments (
page_path,args_json) live in Fragment arguments and restore across configuration changes and process death.
Why this matches Android conventions - Modern Android apps favor one Activity with many Fragments, using Jetpack Navigation for back stack, transitions, and deep links. - It simplifies lifecycle, back handling, and state compared to one-Activity-per-screen.
Comparison to other frameworks¶
- React Native
- Android: single
Activity, screens managed viaFragments (e.g.,react-native-screens). - iOS: screens map to
UIViewControllers pushed onUINavigationController. - .NET MAUI / Xamarin.Forms
- Android: single
Activity, pages via Fragments/Navigation. - iOS: pages map to
UIViewControllers on aUINavigationController. - NativeScript
- Android: single
Activity, pages asFragments. - iOS: pages as
UIViewControllers onUINavigationController. - Flutter (special case)
- Android: single
Activity(FlutterActivity/FlutterFragmentActivity). - iOS:
FlutterViewControllerhosts Flutter’s internal navigator; add-to-app can push multipleFlutterViewControllers.
Bottom line
- iOS: one host VC class, many instances on a UINavigationController.
- Android: one host Activity, many Fragments with Jetpack Navigation.