This guide shows how to navigate between pages and handle lifecycle events.
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)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.
- On Android,
pushnavigates viaNavControllerto aPageFragmentand passespage_pathand optional JSONargs. - On iOS,
pushuses the rootUINavigationControllerto push a newViewControllerand passes page info via KVC.
- 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 useUINavigationControllerfor hierarchical navigation. - The approach integrates cleanly with add-to-app and system behaviors (e.g., state restoration).
- 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.
- React Native
- Android: single
Activity, screens managed viaFragments (e.g.,react-native-screens). - iOS: screens map to
UIViewControllers pushed onUINavigationController.
- Android: single
- .NET MAUI / Xamarin.Forms
- Android: single
Activity, pages via Fragments/Navigation. - iOS: pages map to
UIViewControllers on aUINavigationController.
- Android: single
- NativeScript
- Android: single
Activity, pages asFragments. - iOS: pages as
UIViewControllers onUINavigationController.
- Android: single
- Flutter (special case)
- Android: single
Activity(FlutterActivity/FlutterFragmentActivity). - iOS:
FlutterViewControllerhosts Flutter’s internal navigator; add-to-app can push multipleFlutterViewControllers.
- Android: single
Bottom line
- iOS: one host VC class, many instances on a
UINavigationController. - Android: one host
Activity, manyFragments with Jetpack Navigation.