Repository navigation
Investigate preserving native toolbar presentation across Ionic navigation transitions #296
Description
Problem and direction
The tap-time flash investigated in #292 exposes a broader design question: should fixed native toolbar controls be handed back to the Web during every page transition, or should a native bar remain present while its items transition between pages?
Thanks to @phiamo for identifying the flash and contributing the focused timing change. This investigation follows from that work. It is an architectural investigation, not a decision to replace Ionic routing or require SwiftUI.
Current implementation
- Horizontal controls are individual UIKit views positioned over the WebView. During navigation, suspension restores their Web sources before Ionic starts moving the page, and projection resumes afterward. That handoff can expose a stationary Web header before the slide starts.
- Vertical Bars already use a SwiftUI
NavigationStackand toolbar, and their sources bypass the ordinary moving/suspended-page exclusion. However, that native stack is not synchronized with Ionic's page stack. This is not yet proof of native navigation parity. - Simply overlapping suspension and playback introduces the lifecycle races documented in the review of #292. Those findings still apply.
What was verified
A separate UIKit-only test app was run in the simulator. The attached final recordings are from iPhone 17 Pro / iOS 26.1, built with Xcode 27.1 beta. They contain no Ionic/WebView integration and no custom page animator: the reference uses a root UINavigationController and ordinary animated push/pop.
- Two visibly different pages move horizontally during standard push/pop.
- The trailing item changes from Edit to Finish editing, including a change in its background width, and returns on pop.
- The first round uses the same
UIBarButtonItem.identifieron separate items; the second uses different identifiers. These recordings are not evidence that matching identifiers are necessary or sufficient for a particular morphing effect. - A separate custom-animator experiment with
UIPercentDrivenInteractiveTransitionrestored the source state on cancellation and committed the destination state on completion after programmatic 25%/65% updates (iPhone 26.1 and Duo 27.1). This verifies those state outcomes, not Ionic gesture synchronization or pixel-perfect standard interactive motion.
Normal-speed recording
Approximately 5 s: push with matching identifiers; 8 s: pop. Approximately 13 s / 16 s: push/pop with different identifiers.
native-navigation-verified.mp4
Same recording at quarter speed
This is playback slowed down after recording, not a change to UIKit's animation duration.
native-navigation-slow.mp4
Negative results and limitations
- A standalone
UINavigationBarswitched items immediately in the tested configuration despiteanimated: true. Disabling in-app screenshot capture and replacing repeated frame assignment with Auto Layout did not change that result. The cause is unresolved; this is not a claim that standalone bars can never animate. - The original standalone-bar fixture did not animate page content at all. It could not establish page/bar coordination, so it must not be used as evidence that integration works.
- No direct standalone-bar progress API was found in the inspected public SDK. The successful progress/cancellation experiment required a navigation controller, custom animator and interactive transition driver.
- Search, menus, button groups, accessibility, overlays, mixed Web/native controls, and Ionic swipe-back have not been validated for the proposed architecture.
Relevant UIKit APIs
UIBarButtonItem.identifier, available from iOS 26, lets UIKit match separate items across navigation/toolbar transitions. Without an identifier, UIKit uses position/content heuristics. This supports item correspondence; it does not promise an arbitrary icon-to-icon morph.
Apple also documents standalone navigation bars and interactive view-controller transitions. The latter is a different integration level from merely overlaying a bar.
Proposed next investigation
Before optimizing the suspend/play overlap, evaluate keeping the native bar present through navigation:
- Compare the UIKit reference with SwiftUI's standard
NavigationStacktoolbar behavior. - Establish whether Ionic can remain the sole navigation authority while native presentation follows start/progress/finish/cancel, without conflicting stacks or gestures.
- Keep visual item correspondence separate from action ownership: stale outgoing actions must never be delivered to the wrong page.
- Preserve successful completion versus cancellation through delayed bridge responses and
destroy(); cover short transitions, interrupted preparation and interactive cancellation. - Decide the horizontal rendering approach only after that proof. Keep explicit/manual suspension and genuine Web fallback cases distinct from ordinary navigation.
The question is whether retaining native bar presentation removes the handoff that causes the flash. No production implementation or public API change is proposed by this issue yet.
Activity